file.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package filex
  2. import (
  3. "io"
  4. "os"
  5. )
  6. const bufSize = 1024
  7. // FirstLine returns the first line of the file.
  8. func FirstLine(filename string) (string, error) {
  9. file, err := os.Open(filename)
  10. if err != nil {
  11. return "", err
  12. }
  13. defer file.Close()
  14. return firstLine(file)
  15. }
  16. // LastLine returns the last line of the file.
  17. func LastLine(filename string) (string, error) {
  18. file, err := os.Open(filename)
  19. if err != nil {
  20. return "", err
  21. }
  22. defer file.Close()
  23. return lastLine(filename, file)
  24. }
  25. func firstLine(file *os.File) (string, error) {
  26. var first []byte
  27. var offset int64
  28. for {
  29. buf := make([]byte, bufSize)
  30. n, err := file.ReadAt(buf, offset)
  31. if err != nil && err != io.EOF {
  32. return "", err
  33. }
  34. for i := 0; i < n; i++ {
  35. if buf[i] == '\n' {
  36. return string(append(first, buf[:i]...)), nil
  37. }
  38. }
  39. first = append(first, buf[:n]...)
  40. offset += bufSize
  41. }
  42. }
  43. func lastLine(filename string, file *os.File) (string, error) {
  44. info, err := os.Stat(filename)
  45. if err != nil {
  46. return "", err
  47. }
  48. var last []byte
  49. offset := info.Size()
  50. for {
  51. offset -= bufSize
  52. if offset < 0 {
  53. offset = 0
  54. }
  55. buf := make([]byte, bufSize)
  56. n, err := file.ReadAt(buf, offset)
  57. if err != nil && err != io.EOF {
  58. return "", err
  59. }
  60. if buf[n-1] == '\n' {
  61. buf = buf[:n-1]
  62. n--
  63. } else {
  64. buf = buf[:n]
  65. }
  66. for n--; n >= 0; n-- {
  67. if buf[n] == '\n' {
  68. return string(append(buf[n+1:], last...)), nil
  69. }
  70. }
  71. last = append(buf, last...)
  72. }
  73. }