Working with files

The os package (https://golang.org/pkg/os/) exposes the os.File type which represents a file handle on the system. The os.File type implements several IO primitives, including the io.Reader and io.Writer interfaces, which allows file content to be processed using the standard streaming IO API.

Creating and opening files

The os.Create function creates a new file with the specified path. If the file already exists, os.Create will overwrite it. The os.Open function, on the other hand, opens an existing file for reading.

The following source snippet opens an existing file and creates a copy of its content using the io.Copy function. One common, and recommended practice to notice is the deferred call to the method Close on the file. This ensures a graceful release of OS resources when the function exits:

func main() { 
   f1, err := os.Open("./file0.go") 
   if err != nil { 
         fmt.Println("Unable to open file:", err) 
         os.Exit(1) 
   } 
   defer f1.Close() 
 
   f2, err := os.Create("./file0.bkp") 
   if err != nil { 
         fmt.Println("Unable to create file:", err) 
         os.Exit(1) 
   } 
   defer f2.Close() 
 
   n, err := io.Copy(f2, f1) 
   if err != nil { 
         fmt.Println("Failed to copy:", err) 
         os.Exit(1) 
   } 
 
   fmt.Printf("Copied %d bytes from %s to %s
",  
       n, f1.Name(), f2.Name()) 
} 

golang.fyi/ch10/file0.go

Function os.OpenFile

The os.OpenFile function provides generic low-level functionalities to create a new file or open an existing file with fine-grained control over the file's behavior and its permission. Nevertheless, the os.Open and os.Create functions are usually used instead as they provide a simpler abstraction then the os.OpenFile function.

The os.OpenFile function take three parameters. The first one is the path of the file, the second parameter is a masked bit-field value to indicate the behavior of the operation (for example, read-only, read-write, truncate, and so on) and the last parameter is a posix-compliant permission value for the file.

The following abbreviated source snippet re-implements the file copy code, from earlier. This time, however, it uses the os.FileOpen function to demonstrate how it works:

func main() { 
   f1, err := os.OpenFile("./file0.go", os.O_RDONLY, 0666) 
   if err != nil {...} 
   defer f1.Close() 
 
   f2, err := os.OpenFile("./file0.bkp", os.O_WRONLY, 0666) 
   if err != nil {...} 
   defer f2.Close() 
 
   n, err := io.Copy(f2, f1) 
   if err != nil {...} 
 
   fmt.Printf("Copied %d bytes from %s to %s
",  
      n, f1.Name(), f2.Name()) 
} 

golang.fyi/ch10/file1.go

Note

If you already have a reference to an OS file descriptor, you can also use the os.NewFile function to create a file handle in your program. The os.NewFile function is rarely used, as files are usually initialized using the file functions discussed previously.

Files writing and reading

We have already seen how to use the os.Copy function to move data into or out of a file. Sometimes, however, it will be necessary to have complete control over the logic that writes or reads file data. The following code snippet, for instance, uses the WriteString method from the os.File variable, fout, to create a text file:

func main() { 
   rows := []string{ 
         "The quick brown fox", 
         "jumps over the lazy dog", 
   } 
 
   fout, err := os.Create("./filewrite.data") 
   if err != nil { 
         fmt.Println(err) 
         os.Exit(1) 
   } 
   defer fout.Close() 
 
   for _, row := range rows { 
         fout.WriteString(row) 
   } 
} 

golang.fyi/ch10/filewrite0.go

If, however, the source of your data is not text, you can write raw bytes directly to the file as shown in the following source snippet:

func main() { 
   data := [][]byte{ 
         []byte("The quick brown fox
"), 
         []byte("jumps over the lazy dog
"), 
   } 
   fout, err := os.Create("./filewrite.data") 
   if err != nil { ... } 
   defer fout.Close() 
 
   for _, out := range data { 
         fout.Write(out) 
   } 
} 

golang.fyi/ch10/filewrite0.go

As an io.Reader, reading from of the io.File type directly can be done using the Read method. This gives access to the content of the file as a raw stream of byte slices. The following code snippet reads the content of file ../ch0r/dict.txt as raw bytes assigned to slice p up to 1024-byte chunks at a time:

func main() { 
   fin, err := os.Open("../ch05/dict.txt") 
   if err != nil { 
         fmt.Println(err) 
         os.Exit(1) 
   } 
   defer fin.Close() 
   p := make([]byte, 1024) 
   for { 
         n, err := fin.Read(p) 
         if err == io.EOF { 
               break 
         } 
         fmt.Print(string(p[:n])) 
   } 
} 

golang.fyi/ch10/fileread.go

Standard input, output, and error

The os package includes three pre-declared variables, os.Stdin, os.Stdout, and os.Stderr, that represent file handles for standard input, output, and error of the OS respectively. The following snippet reads the file f1 and writes its content to io.Stdout, standard output, using the os.Copy function (standard input is covered later):

func main() { 
   f1, err := os.Open("./file0.go") 
   if err != nil { 
         fmt.Println("Unable to open file:", err) 
         os.Exit(1) 
   } 
   defer f1.Close() 
 
   n, err := io.Copy(os.Stdout, f1) 
   if err != nil { 
         fmt.Println("Failed to copy:", err) 
         os.Exit(1) 
   } 
 
   fmt.Printf("Copied %d bytes from %s 
", n, f1.Name()) 
} 

golang.fyi/ch10/osstd.go

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.114.19