mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-10 08:29:58 +08:00
chore: optimize file reading (#4264)
This commit is contained in:
@@ -61,25 +61,26 @@ func lastLine(filename string, file *os.File) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
bf := int64(bufSize)
|
|
||||||
var last []byte
|
var last []byte
|
||||||
|
bufLen := int64(bufSize)
|
||||||
offset := info.Size()
|
offset := info.Size()
|
||||||
for {
|
|
||||||
if offset < bufSize {
|
for offset > 0 {
|
||||||
bf = offset
|
if offset < bufLen {
|
||||||
|
bufLen = offset
|
||||||
offset = 0
|
offset = 0
|
||||||
} else {
|
} else {
|
||||||
offset -= bf
|
offset -= bufLen
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, bf)
|
buf := make([]byte, bufLen)
|
||||||
n, err := file.ReadAt(buf, offset)
|
n, err := file.ReadAt(buf, offset)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return "", nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if buf[n-1] == '\n' {
|
if buf[n-1] == '\n' {
|
||||||
@@ -89,16 +90,14 @@ func lastLine(filename string, file *os.File) (string, error) {
|
|||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
}
|
}
|
||||||
|
|
||||||
for n--; n >= 0; n-- {
|
for i := n - 1; i >= 0; i-- {
|
||||||
if buf[n] == '\n' {
|
if buf[i] == '\n' {
|
||||||
return string(append(buf[n+1:], last...)), nil
|
return string(append(buf[i+1:], last...)), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last = append(buf, last...)
|
last = append(buf, last...)
|
||||||
|
|
||||||
if offset == 0 {
|
|
||||||
return string(last), nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return string(last), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,3 +164,57 @@ func TestLastLineEmptyFile(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "", val)
|
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)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user