Files: GoLang
Learning a new syntax and the libraries is always a task, and the only way forward is gradual. In this blog I will try to create a small program to read a text file and will keep updating the program to include more sophistication
Code: File
I will give you the complete code and then explain what all I have done
package files
import (
"bufio"
"fmt"
"io"
"log"
"os"
)
func message(m string) {
log.Printf(" FILES: %s", m)
}
// ReadFile reads the file and dump contents
func ReadFile(fn string) {
message("ReadFile Invoked")
fh, err := os.OpenFile(fn, os.O_RDONLY, 0666)
if err != nil {
message(" Unable to open file " + fn)
os.Exit(1)
}
defer fh.Close()
defer message(" Closing the handle")
fr := bufio.NewReader(fh)
for {
li, err := fr.ReadString('\n')
if err == nil {
fmt.Printf(" ><: %s", li)
continue
} else if err == io.EOF {
fmt.Println(" --- End of File ---")
break
}
fmt.Println(" Error:", err)
break
}
}
Step 1: Define the package
I keep the logic separate form the main
package as a habit, and continuing the trend; I define a package files
here.
package files
imports
will be explained later, but lets define a helper function – message
.
Step 2: Function message
func message(m string) {
log.Printf(" FILES: %s", m)
}
The primary purpose of this is printing a debug message with a predefined prefix FILES:
Example
2021/01/21 18:46:30 FILES: ReadFile Invoked
Step 3: Function ReadFile
Let’s write the function that will read the actual file which will be passed as an argument.
Invoking this function is as easy as importing the
package
and callingfiles.ReadFile
Arguments: fn – FileName
The ReadFile
shall take an argument the file-name
that needs to be read for contents. The objective of this function is simple – Dump everything on the STDOUT.
package os
– Link
Package os
allows a platform independent interface to Operating System functionality and hence the name O.S.
Function – OpenFile
The primary function we will be using the OpenFile
. It opens the specified name with the specified flags.
fh, err := os.OpenFile(fn, os.O_RDONLY, 0666)
The official documentation defines the signature of the function as
func OpenFile(name string, flag int, perm FileMode) (*File, error)
Returning the FileHandle – fh
and in case of error err
.
More about the File
can be found here.
Check for error which can indicate file open was failure.
if err != nil {
message(" Unable to open file " + fn)
os.Exit(1)
}
Example: readme1.txt
In case the file doesn’t exists the error message as below can be seen
2021/01/21 22:45:04 FILES: Unable to open file readme1.txt
A deferred call to close the file. Which shall render the fh
useless for io
operation.
defer fh.Close()
defer message(" Closing the handle")
ReadContents: BufferedReader
After opening the file it is time to read the contents, for this we will use a bufio
package.
NewReader
Using the filehandle – fh
lets create a reader fr
.
fr := bufio.NewReader(fh)
Ideally you should check for nil
before you proceed to reading the contents. I am using the ReadString
from the reader.
func (b *Reader) ReadString(delim byte) (string, error)
It will read till the occurrence of the first newline (delimiter)
li, err := fr.ReadString('\n')
rest of the code is quite simple that processes
- Checking error for the invocation of
ReadString
- If no error – dump the contents on stdout
- In case of error check if it is
EOF
- Else, show the nature of error and break out of the
for
loop.
if err == nil {
fmt.Printf(" ><: %s", li)
continue
} else if err == io.EOF {
fmt.Println(" --- End of File ---")
break
}
fmt.Println(" Error:", err)
break