go input and output streams (ioutil)

Although the io package provides many types, methods and functions, it is sometimes not so convenient to use. Such as reading all the contents of a file. To this end, the standard library provides some common and convenient IO operation functions.

Note: These functions are relatively simple to use, and generally do not give examples.

1.1. NopCloser function

Sometimes we need to pass an instance of io.ReadCloser, and we now have an instance of io.Reader, such as: strings.Reader, this time NopCloser comes in handy. It wraps an io.Reader and returns an io.ReadCloser, while the corresponding Close method does nothing but returns nil.

For example, NewRequest in the standard library net/http package receives an io.Reader body, but in fact, the type of Request's Body is io.ReadCloser. Therefore, the code is judged internally, if the passed io.Reader is also If the io.ReadCloser interface is implemented, convert it, otherwise wrap it with ioutil.NopCloser and convert it. The relevant code is as follows:

rc, ok := body.(io.ReadCloser)
if !ok && body != nil {
    rc = ioutil.NopCloser(body)
}

Without this function, we would have to implement one ourselves. Of course, the implementation is very simple, the reader can take a look at the implementation of NopCloser.

1.2. ReadAll function

Many times, we need to read the data in io.Reader at one time. Through the explanation in the previous section, we know that there are many ways to implement it. Considering that there are many needs to read all data, Go provides the ReadAll function to read all data from io.Reader at once.

func ReadAll(r io.Reader) ([]byte, error)

Reading the source code of this function found that it reads all data through ReadFrom in bytes.Buffer.

1.3. ReadDir function

Written question: write a program to output all files in a directory (including subdirectories)

Have you ever seen a test question like this?

How to output all files in a directory in Go? First of all, we will think of checking the os package to see if the File type provides relevant methods (about the os package, which will be explained later).

In fact, a convenient function is provided in ioutil: ReadDir, which reads a directory and returns the sorted file and subdirectory names ([]os.FileInfo). Through this method, we can easily implement "interview questions".

The following example implements the tree command similar to Unix, but it also works fine under Windows.

// 未实现-L参数功能
func main() {
    if len(os.Args) > 1 {
        Tree(os.Args[1], 1, map[int]bool{1:true})
    }
}

// 列出dirname目录中的目录树,实现类似Unix中的tree命令
// curHier 当前层级(dirname为第一层)
// hierMap 当前层级的上几层是否需要'|'的映射
func Tree(dirname string, curHier int, hierMap map[int]bool) error {
    dirAbs, err := filepath.Abs(dirname)
    if err != nil {
        return err
    }
    fileInfos, err := ioutil.ReadDir(dirAbs)
    if err != nil {
        return err
    }

    fileNum := len(fileInfos)
    for i, fileInfo := range fileInfos {
        for j := 1; j < curHier; j++ {
            if hierMap[j] {
                fmt.Print("|")
            } else {
                fmt.Print(" ")
            }
            fmt.Print(strings.Repeat(" ", 3))
        }

        // map是引用类型,所以新建一个map
        tmpMap := map[int]bool{}
        for k, v := range hierMap {
            tmpMap[k] = v
        }
        if i+1 == fileNum {
            fmt.Print("`")
            delete(tmpMap, curHier)
        } else {
            fmt.Print("|")
            tmpMap[curHier] = true
        }
        fmt.Print("-- ")
        fmt.Println(fileInfo.Name())
        if fileInfo.IsDir() {
            Tree(filepath.Join(dirAbs, fileInfo.Name()), curHier+1, tmpMap)
        }
    }
    return nil
}

1.4. ReadFile and WriteFile functions

ReadFile reads the content of the entire file. In the previous section, we implemented a function to read the entire content of the file. Since this requirement is very common, Go provides the ReadFile function for ease of use. The implementation of ReadFile is similar to ReadAll. However, ReadFile will first determine the size of the file and give bytes.Buffer a predefined capacity to avoid additional memory allocation.

The signature of the WriteFile function is as follows:

func WriteFile(filename string, data []byte, perm os.FileMode) error

It writes data to the filename file, and creates one when the file does not exist (the file permissions are specified by perm); otherwise, the file content will be emptied first. For the perm parameter, we can generally specify it as: 0666, the specific meaning is explained in the os package.

hint

The size of the file is obtained first in the ReadFile source code, and the size of the file is used only when the size is < 1e9. According to the comments in the source code, FileInfo does not get the file size very accurately.

1.5. TempDir and TempFile functions

Temporary directories are generally provided in the operating system, such as the /tmp directory under linux (which can be obtained through os.TempDir()). Sometimes, we need to create a temporary directory ourselves, such as in the source code of the Go toolchain (src/cmd/go/build.go), and create a temporary directory through TempDir to store temporary files for the compilation process:

b.work, err = ioutil.TempDir("", "go-build")

If the first parameter is empty, it indicates that a temporary directory is created in the system default temporary directory (os.TempDir); the second parameter specifies the prefix of the temporary directory name, and the function returns the path of the temporary directory.

Correspondingly, TempFile is used to create temporary files. For example, create a temporary file in the source code of the gofmt command:

f1, err := ioutil.TempFile("", "gofmt")

The parameters have similar meanings to the ioutil.TempDir parameter.

这里需要注意:创建者创建的临时文件和临时目录要负责删除这些临时目录和文件。如删除临时文件:

defer func() {
    f.Close()
    os.Remove(f.Name())
}()

1.6. Discard 变量

Discard 对应的类型(type devNull int)实现了io.Writer接口,同时,为了优化io.Copy到Discard,避免不必要的工作,实现了io.ReaderFrom接口。

devNull 在实现io.Writer接口时,只是简单的返回(标准库文件:src/pkg/io/ioutil.go)。

func (devNull) Write(p []byte) (int, error) {
    return len(p), nil
}

而ReadFrom的实现是读取内容到一个buf中,最大也就8192字节,其他的会丢弃(当然,这个也不会读取)。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325416460&siteId=291194637