I'm trying to read lines in files. I'd like to easily open a file, and parse through the lines one at a time, and remove some boilerplate opening and closing. I'm passing back a pointer to the 'scanner'. Is this just a dumb approach? Has the scanner already read the contents because of the Split? Are there better ways of doing this? Any insight regarding best practices are appreciated.
func main() {
var path string
if len(os.Args) > 1 {
err, scanner := fileScanner(path)
if err == nil {
// Go through file line by line.
for scanner.Scan() {
fmt.Println(scanner.Text())
// or do other stuff
}
// so how do I make sure to close the file?
}
}
}
// Return a scanner for a file.
func fileScanner(path string) *bufio.Scanner {
file, err := os.Open(path)
if err != nil {
return err
}
//defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
return err, scanner
}
I think the simplest solution is just not to open the file in your fileScanner
function.
If it's really important for you to extract these operations out of your main function then consider creating a new struct type that holds both your scanner and your file pointer and then you can define methods on that type to open, close and get the scanner. Something along these lines:
type fileScanner struct {
File *os.File
Scanner *bufio.Scanner
}
func NewFileScanner() *fileScanner {
return &fileScanner{}
}
func (f *fileScanner) Open(path string) (err error) {
f.File, err = os.Open(path)
return err
}
func (f *fileScanner) Close() error {
return f.File.Close()
}
func (f *fileScanner) GetScanner() *bufio.Scanner {
if f.Scanner == nil {
f.Scanner = bufio.NewScanner(f.File)
f.Scanner.Split(bufio.ScanLines)
}
return f.Scanner
}
func main() {
var path string
if len(os.Args) > 1 {
fscanner := NewFileScanner()
err := fscanner.Open(path)
if err == nil {
defer fscanner.Close()
scanner := fscanner.GetScanner()
// Go through file line by line.
for scanner.Scan() {
fmt.Println(scanner.Text())
// or do other stuff
}
}
}
}
Which is rather a lot of work for this purpose. Other alternatives are to return the file from your function (though you should handle panics to avoid any possible leaks) or to return a cleanup function.