diff --git a/os/gfile/gfile_contents.go b/os/gfile/gfile_contents.go index b933d1f78..e4a8e48e9 100644 --- a/os/gfile/gfile_contents.go +++ b/os/gfile/gfile_contents.go @@ -169,19 +169,7 @@ func GetBytesByTwoOffsetsByPath(path string, start int64, end int64) []byte { // // Note that the parameter passed to callback function might be an empty value, and the last non-empty line // will be passed to callback function even if it has no newline marker. -func ReadLines(file string, callback func(text string)) error { - cb := func(bytes []byte) { - callback(gconv.UnsafeBytesToStr(bytes)) - } - return ReadByteLines(file, cb) -} - -// ReadByteLines reads file content line by line, which is passed to the callback function as []byte. -// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker. -// -// Note that the parameter passed to callback function might be an empty value, and the last non-empty line -// will be passed to callback function even if it has no newline marker. -func ReadByteLines(file string, callback func(bytes []byte)) error { +func ReadLines(file string, callback func(text string) error) error { f, err := os.Open(file) if err != nil { return err @@ -189,9 +177,42 @@ func ReadByteLines(file string, callback func(bytes []byte)) error { defer f.Close() scanner := bufio.NewScanner(f) - for scanner.Scan() { - callback(scanner.Bytes()) + if err = callback(scanner.Text()); err != nil { + return err + } + } + return nil +} + +// ReadByteLines reads file content line by line, which is passed to the callback function as []byte. +// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker. +// +// Note that the parameter passed to callback function might be an empty value, and the last non-empty line +// will be passed to callback function even if it has no newline marker. +// +// Deprecated, use ReadLinesBytes instead. +func ReadByteLines(file string, callback func(bytes []byte) error) error { + return ReadLinesBytes(file, callback) +} + +// ReadLinesBytes reads file content line by line, which is passed to the callback function as []byte. +// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker. +// +// Note that the parameter passed to callback function might be an empty value, and the last non-empty line +// will be passed to callback function even if it has no newline marker. +func ReadLinesBytes(file string, callback func(bytes []byte) error) error { + f, err := os.Open(file) + if err != nil { + return err + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + if err = callback(scanner.Bytes()); err != nil { + return err + } } return nil } diff --git a/os/gfile/gfile_z_readline_test.go b/os/gfile/gfile_z_readline_test.go index 76e956250..7c92efe05 100644 --- a/os/gfile/gfile_z_readline_test.go +++ b/os/gfile/gfile_z_readline_test.go @@ -1,4 +1,4 @@ -// Copyright 2017-2018 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, @@ -8,6 +8,7 @@ package gfile_test import ( "github.com/gogf/gf/debug/gdebug" + "github.com/gogf/gf/errors/gerror" "testing" "github.com/gogf/gf/os/gfile" @@ -17,7 +18,8 @@ import ( func Test_NotFound(t *testing.T) { gtest.C(t, func(t *gtest.T) { teatFile := gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/error.log" - callback := func(line string) { + callback := func(line string) error { + return nil } err := gfile.ReadLines(teatFile, callback) t.AssertNE(err, nil) @@ -26,34 +28,60 @@ func Test_NotFound(t *testing.T) { func Test_ReadLines(t *testing.T) { gtest.C(t, func(t *gtest.T) { - expectList := []string{"a", "b", "c", "d", "e"} - - getList := make([]string, 0) - callback := func(line string) { - getList = append(getList, line) - } - - teatFile := gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/file.log" + var ( + expectList = []string{"a", "b", "c", "d", "e"} + getList = make([]string, 0) + callback = func(line string) error { + getList = append(getList, line) + return nil + } + teatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/file.log" + ) err := gfile.ReadLines(teatFile, callback) - t.AssertEQ(getList, expectList) t.AssertEQ(err, nil) }) } -func Test_ReadByteLines(t *testing.T) { +func Test_ReadLines_Error(t *testing.T) { gtest.C(t, func(t *gtest.T) { - expectList := [][]byte{[]byte("a"), []byte("b"), []byte("c"), []byte("d"), []byte("e")} - - getList := make([][]byte, 0) - callback := func(line []byte) { - getList = append(getList, line) - } - - teatFile := gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/file.log" - err := gfile.ReadByteLines(teatFile, callback) + var ( + callback = func(line string) error { + return gerror.New("custom error") + } + teatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/file.log" + ) + err := gfile.ReadLines(teatFile, callback) + t.AssertEQ(err.Error(), "custom error") + }) +} +func Test_ReadLinesBytes(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + expectList = [][]byte{[]byte("a"), []byte("b"), []byte("c"), []byte("d"), []byte("e")} + getList = make([][]byte, 0) + callback = func(line []byte) error { + getList = append(getList, line) + return nil + } + teatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/file.log" + ) + err := gfile.ReadLinesBytes(teatFile, callback) t.AssertEQ(getList, expectList) t.AssertEQ(err, nil) }) } + +func Test_ReadLinesBytes_Error(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + callback = func(line []byte) error { + return gerror.New("custom error") + } + teatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/readline/file.log" + ) + err := gfile.ReadLinesBytes(teatFile, callback) + t.AssertEQ(err.Error(), "custom error") + }) +}