chore: optimize file reading (#4264)

This commit is contained in:
Kevin Wan 2024-07-20 22:44:13 +08:00 committed by GitHub
parent 9de04ee035
commit 0eec33f14b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 14 deletions

View File

@ -61,25 +61,26 @@ func lastLine(filename string, file *os.File) (string, error) {
return "", err
}
bf := int64(bufSize)
var last []byte
bufLen := int64(bufSize)
offset := info.Size()
for {
if offset < bufSize {
bf = offset
for offset > 0 {
if offset < bufLen {
bufLen = offset
offset = 0
} else {
offset -= bf
offset -= bufLen
}
buf := make([]byte, bf)
buf := make([]byte, bufLen)
n, err := file.ReadAt(buf, offset)
if err != nil && err != io.EOF {
return "", err
}
if n == 0 {
return "", nil
break
}
if buf[n-1] == '\n' {
@ -89,16 +90,14 @@ func lastLine(filename string, file *os.File) (string, error) {
buf = buf[:n]
}
for n--; n >= 0; n-- {
if buf[n] == '\n' {
return string(append(buf[n+1:], last...)), nil
for i := n - 1; i >= 0; i-- {
if buf[i] == '\n' {
return string(append(buf[i+1:], last...)), nil
}
}
last = append(buf, last...)
if offset == 0 {
return string(last), nil
}
}
return string(last), nil
}

View File

@ -164,3 +164,57 @@ func TestLastLineEmptyFile(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, "", val)
}
func TestFirstLineExactlyBufSize(t *testing.T) {
content := make([]byte, bufSize)
for i := range content {
content[i] = 'a'
}
content[bufSize-1] = '\n' // Ensure there is a newline at the edge
filename, err := fs.TempFilenameWithText(string(content))
assert.Nil(t, err)
defer os.Remove(filename)
val, err := FirstLine(filename)
assert.Nil(t, err)
assert.Equal(t, string(content[:bufSize-1]), val)
}
func TestLastLineExactlyBufSize(t *testing.T) {
content := make([]byte, bufSize)
for i := range content {
content[i] = 'a'
}
content[bufSize-1] = '\n' // Ensure there is a newline at the edge
filename, err := fs.TempFilenameWithText(string(content))
assert.Nil(t, err)
defer os.Remove(filename)
val, err := LastLine(filename)
assert.Nil(t, err)
assert.Equal(t, string(content[:bufSize-1]), val)
}
func TestFirstLineLargeFile(t *testing.T) {
content := text + text + text + "\n" + "extra"
filename, err := fs.TempFilenameWithText(content)
assert.Nil(t, err)
defer os.Remove(filename)
val, err := FirstLine(filename)
assert.Nil(t, err)
assert.Equal(t, "first line", val)
}
func TestLastLineLargeFile(t *testing.T) {
content := text + text + text + "\n" + "extra"
filename, err := fs.TempFilenameWithText(content)
assert.Nil(t, err)
defer os.Remove(filename)
val, err := LastLine(filename)
assert.Nil(t, err)
assert.Equal(t, "extra", val)
}