Go -- File Operation

1. Opening and closing files

  • The os.Open() function opens a file and returns a *File and an err. Calling the close() method on the resulting file instance closes the file.

2. Reading Files

1. file.Read() Reads the file

  • It receives a byte slice and stores the read data in a temporary slice, returning the number of bytes read and possible specific errors, and returns 0 and io.EOF at the end of the file.
  • This specified byte reading has a flaw, for example, Chinese takes up three characters and may be scrambled when slicing.

Example:

func main() {
	// Open File
	fileobj, err := os.Open("./main.go")
	if err != nil {
		fmt.Printf("open file failed, Err:%v", err)
		return
	}
	// Remember to close the file
	defer fileobj.Close()
	// read file
	var tmp [128]byte // Defines an array of 128 byte elements to hold read data
	for {
		/* fileobj.Read()Method () passes in an array or slice of byte type as a container to store the data in the array or slice.
		For example, ttmp[:64] means 64 bytes at a time, [:] means 128 bytes at a time.
		 fileobj.Read()Method returns read values and error information */
		n, err := fileobj.Read(tmp[:64])
		if err != nil {
			fmt.Println("read file failed , err:%v", err)
			return
		}
		fmt.Printf("Read %d Bytes", n)
		fmt.Println(string(tmp[:n]))
		if n < 64 {
			return
		}
	}
}

2. bufio Read Files

  • bufio encapsulates an API based on file to support more functions.
  • Buffio needs to declare an instance object to use it to remove methods encapsulated in buffio

Example

func readFromBuffio() {
	fileobj, err := os.Open("./main.go")
	if err != nil {
		fmt.Printf("The file failed to open. err:%v", err)
		return
	}
	defer fileobj.Close()
	// Declare an object to read a file
	reader := bufio.NewReader(fileobj)
	for {
	// The ReadString() method also returns two values, data and error information, () is passed in a separator, you can specify a behavior separator, note: character is passed in
		line, err := reader.ReadString('\n') // Note that () is passed in a character, not a string, so it is a single quotation mark indicating that it is read as a string and on a line of'\n'.
		if err == io.EOF { // If the error message is io.EOF, the read is complete and there is no line divider
			if len(line) != 0 {  // Determine if the last row has data and print if it does
				fmt.Print(line)
			}
			fmt.Println("File Read End")
			break
		}
		if err != nil {
			fmt.Printf("fail to read file,err:%v", err)
			return
		}
		fmt.Print(line)
	}
}
func main() {
	readFromBuffio()
}

3. ioutil reads the entire file

  • The ReadFile method of the io/ioutil package reads the entire file, simply passing in the file name as a parameter.
func readFeilFromIoutil() {
	// Using the ioutil.ReadFile() method, pass in the file name and directly open the contents of the read file
	content, err := ioutil.ReadFile("./main.go")
	if err != nil {
		fmt.Printf("read file falied,Err:%v\n", err)
		return
	}
	fmt.Println(string(content))
}
func main() {
	readFeilFromIoutil()
}

3. File Writing Operation

  • The os.OpenFile() function can open a file in a specified mode, thereby enabling file writing.
    • The os.Open() above can only be opened read-only
  • The source code signature is as follows
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
	...
}
# Where:
#    Name: the name of the file to open 
#    flag: The mode in which files are opened. Multiple flags are represented by | logic or separation (logical or computational representation of the binary numbers used at the bottom of the file mode)
#    perm: file permissions, an octal number. r (read) 04, w (write) 02, x (execute) 01.

There are several open modes for files:

PatternMeaning
os.O_WRONLYWrite-only
os.O_CREATEcreate a file
os.O_RDONLYread-only
os.O_RDWRRead and Write
os.O_TRUNCempty
os.O_APPENDAppend
  • View the definitions of various modes
const (
	// Invented values to support what package os expects.
	O_RDONLY   = 0x00000     // 0000 0000 0000
	O_WRONLY   = 0x00001     // 0000 0000 0001
	O_RDWR     = 0x00002     // 0000 0000 0010
	O_CREAT    = 0x00040     // 0000 0100 0000
	O_EXCL     = 0x00080     // 0000 1000 0000
	O_NOCTTY   = 0x00100     // 0001 0000 0000
	O_TRUNC    = 0x00200     // 0010 0000 0000
	O_NONBLOCK = 0x00800     // 1000 0000 0000
	O_APPEND   = 0x00400     // 0100 0000 0000
	O_SYNC     = 0x01000     
	O_ASYNC    = 0x02000     
	O_CLOEXEC  = 0x80000     
)

# You can see that various modes have constants of type int, hexadecimal data, converted to binary for logical or, you can see that each mode does not conflict (that is, the position of 1 determines the file open mode)
# If O_RDWR|O_CREAT = 0000 0100 0010, then the binary number 0000 0100 0010 represents both read, write and create

1. Write and WriteString

  • Write() writes byte slice data
  • WriteString() writes string data directly

Examples;

func wirteFile() {
	// Open File
	file, err := os.OpenFile("./abc.txt", os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		fmt.Printf("file open failed, Err:%v\n", err)
		return
	}
	defer file.Close()
	// Write() method, slice of byte type passed in
	file.Write([]byte("Hello!!\n"))
	// WriteString() method, passing in a string directly
	file.WriteString("I am well known\n")
}

func main() {
	wirteFile()
}

2,bufio.NewWriter

  • Usage of bufio.NewWriter and bufio.NewReader type, object needs to be declared first
func writeFileByBuffio() {
	file, err := os.OpenFile("./123.txt", os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		fmt.Printf("file open failed, Err:%v\n", err)
		return
	}
	defer file.Close()
	// You also need to declare a written object, and the file handle is passed in the NewWriter() method
	writer := bufio.NewWriter(file)
	writer.Write([]byte("Hello "))   // Slice of byte when data is passed in by the Write() method
	writer.WriteString("World !!")   // WriteString() method directly mixes in strings
	writer.Flush()    // Note: File write operation, after Flush() is executed, the data in the cache is written to the file before the operation is completed
}

func main() {
	writeFileByBuffio()
}

3,ioutil.WriteFile

  • Write directly

Example:

func writeFileByIoutil() {
	str := "Hello, I'm Piggy Page!*\n I'm going to eat you"
	err := ioutil.WriteFile("./new.txt", []byte(str), 0644)
	if err != nil {
		fmt.Printf("file open failed, Err:%v\n", err)
		return
	}
}
func main() {
	writeFileByIoutil()
}

4. Using io.Copy to copy files

  • The io.Copy() method passes in two objects, read and write
    View Source Code
func Copy(dst Writer, src Reader) (written int64, err error) {
	return copyBuffer(dst, src, nil)
}

Example:

func CopyFile(destFile, srcFile string) (written int64, err error) {
	srcfileobj, err := os.Open(srcFile)
	if err != nil {
		fmt.Printf("The file failed to open. err:%v", err)
		return
	}

	destFileobj, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		fmt.Printf("The file failed to open. err:%v", err)
		return
	}
	defer destFileobj.Close()
	defer srcfileobj.Close()
	return io.Copy(destFileobj, srcfileobj)
}

func main() {
	CopyFile("./test.txt", "./main.go")
}

5. Use buffio to get user input string with spaces

  • When the direct fmt.Scanln() method asks the user to enter a string, it is found that a string with spaces cannot be entered because fmt.Scanln() defaults to a space return as the delimiter, so the output will always be the character before the first space

An example is as follows: When a user enters a space character, for example, a b c, the result returns only a

func main() {
	var str string
	fmt.Print("Please enter:")
	fmt.Scanln(&str)
	fmt.Println(str)
}

Output Results

Please enter:a b c
a
  • Therefore, buffio needs to be used for optimization
    Example: Use os.Stdin to get standard input and divide the input into different behaviors
func main() {
	var str string
	fmt.Print("Please enter:")
	reader := bufio.NewReader(os.Stdin)
	str, _ = reader.ReadString('\n')
	fmt.Println(str)
}

Practice

  • Implement a cat command
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
)

// cat command implementation
func cat(r *bufio.Reader) {
	for {
		buf, err := r.ReadBytes('\n') //Note is character
		if err == io.EOF {
			// Output Read Before Exiting
			fmt.Fprintf(os.Stdout, "%s", buf)
			break
		}
		fmt.Fprintf(os.Stdout, "%s", buf)
	}
}

func main() {
	flag.Parse() // Parse command line parameters
	if flag.NArg() == 0 {
		// If there are no parameters, read from standard input by default
		cat(bufio.NewReader(os.Stdin))
	}
	// Read the contents of each specified file in turn and print to the terminal
	for i := 0; i < flag.NArg(); i++ {
		f, err := os.Open(flag.Arg(i))
		if err != nil {
			fmt.Fprintf(os.Stdout, "reading from %s failed, err:%v\n", flag.Arg(i), err)
			continue
		}
		cat(bufio.NewReader(f))
	}
}

Keywords: Go

Added by kujtim on Tue, 21 Sep 2021 13:20:24 +0300