Friday, February 22, 2019

File Handling in Go - Part 2

In the Part 1 of this lesson, we learned how to open, read and write to files using Go Language. In this lesson, we shall learn about other file handling related functions provided by Go language.

Seeking

We often need to seek into a file to a particular point and then do read or write. For there is a seek() function provided by os package.


func (f *File) Seek(offset int64, whence int) (ret int64, err error)

 Seek() function takes two arguments, offset and whence. whence tells the function from where to seek and offset tells how much to seek. 
whence can have one of the following values:
  • 0 - Seek From beginning
  • 1 - Seek from current position in file
  • 2 - Seek from end
So, e.g.

Seek(0,0) is going to seek to the start of the file.
Seek(0,2) is going to seek to the end of the file.
Seek(10,0) is going to seek 10 bytes from the start of the file.

Let's look at a program that uses the Seek() function.


package main
import (
    "fmt"
    "os"
)

func main() {
    f,err := os.Open("file-1.txt")

    if err != nil {
        fmt.Println("Error in Opening file",err)
        os.Exit(1)
    }

    //Seek 10 bytes from the start of file
    offset,err := f.Seek(10,0);

    if err != nil {
        fmt.Println("Error in Seeking",err)
        os.Exit(1)
    }

    // Make a buffer to read data from the file
    buf := make([]byte,10)

    //Read some bytes from the file
    readbytes, err := f.Read(buf)

    if err != nil {
        fmt.Println("Error in reading from file",err)
        os.Exit(1)
    }

    //Print the data read from file
    fmt.Println("Data read from file from offset",offset,readbytes)
    fmt.Printf("%s\n",buf)


    //Seek to the start of the file
    offset,err = f.Seek(0,0)

    if err != nil {
        fmt.Println("Error in seeking to front",err)
        os.Exit(1)
    }

    // Read some bytes from the start of the file
    readbytes,err = f.Read(buf)

    if err != nil {
        fmt.Println("Error in reading from file",err)
        os.Exit(1)
    }

    fmt.Println("Data read from file from offset",offset,"Total bytes read",readbytes);
    fmt.Printf("%s\n",buf)


    //Seek to the end of file
    offset, err = f.Seek(0,2)

    if err != nil {
        fmt.Println("Error in seeking to end",err)
        os.Exit(1)
    }

    fmt.Println("File-Offset",offset)
}

So, I created a file called file-1.txt and ran the above program. Notice that, at the end of the program, we seek to the end of the file. If you attempt to read further from this point on, you should get a EOF error.

The one thing, that you need to remember while using the Seek() function is that the behavior of Seek() is unspecified if the file has been opened in APPEND mode. So you should avoid using Seek() when file is opened in APPEND mode.


File Stat - Getting to know about a file


The stat() function provides us with useful information about a file that already exists in your system.

func (f *File) Stat() (FileInfo, error)

Stat() function returns a FileInfo object that contains all the information about the file. 


FileInfo provides relevant information about the file.


type FileInfo interface {
 Name() string       // base name of the file
 Size() int64        // size of file
 Mode() FileMode     // file mode bits
 ModTime() time.Time // modification time
 IsDir() bool        // Is file a directory
 Sys() interface{}   // underlying data source (can return nil)
}


Here is a sample program, that shows the usage of stat() function.


package main

import (
    "fmt"
    "os"
)

func main() {
    f, err := os.Open("file-1.txt")

    if err != nil {
        fmt.Println("Err in Opening file",err)
        os.Exit(1)
    }

    finfo, err := f.Stat()

    if err != nil {
        fmt.Println("Err in file stat",err)
        os.Exit(1)
    }

    fmt.Println("Name of the file:", finfo.Name())
    fmt.Println("Size of the file:", finfo.Size(), "bytes")
    fmt.Println("Mode of the file:", finfo.Mode())
    fmt.Println("Is the file a directory:", finfo.IsDir())
}


Alternatively one could simple use the Stat() function by providing the name of file. In that case, you don't need to open the file for a file object.   

    finfo, err := os.Stat("File-1.txt") 


There are a whole lot of other functions provided by os package, that you can find in Golang OS package documentation. Check it out and use the functions as per your need.

Feel free to comment on what is missing or could be enhanced in this lesson. 

No comments:

Post a Comment