file.go 1.4 KB

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