Go语言常用文件操作汇总

Share on:
一切都是文件

UNIX的基本方面之一是一切都是文件。我们不一定知道文件描述符所映射的内容,这是由操作系统的设备驱动程序抽象的。操作系统以文件形式为我们提供了到设备的接口。
Go中的读取器和写入器接口是相似的抽象。我们只需读取和写入字节,而无需了解读取器从何处或如何获取数据或写入器在何处发送数据。 在/dev中查找可用的设备。 有些将需要提升的特权才能访问。

创建空文件
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8var (
 9    newFile *os.File
10    err     error
11)
12
13func main() {
14    newFile, err = os.Create("test.txt")
15    if err != nil {
16        log.Fatal(err)
17    }
18    log.Println(newFile)
19    newFile.Close()
20}
截取文件
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8func main() {
 9    // Truncate a file to 100 bytes. If file
10    // is less than 100 bytes the original contents will remain
11    // at the beginning, and the rest of the space is
12    // filled will null bytes. If it is over 100 bytes,
13    // Everything past 100 bytes will be lost. Either way
14    // we will end up with exactly 100 bytes.
15    // Pass in 0 to truncate to a completely empty file
16
17    err := os.Truncate("test.txt", 100)
18    if err != nil {
19        log.Fatal(err)
20    }
21}
获取文件信息
 1package main
 2
 3import (
 4    "fmt"
 5    "log"
 6    "os"
 7)
 8
 9var (
10    fileInfo os.FileInfo
11    err      error
12)
13
14func main() {
15    // Stat returns file info. It will return
16    // an error if there is no file.
17    fileInfo, err = os.Stat("test.txt")
18    if err != nil {
19        log.Fatal(err)
20    }
21    fmt.Println("File name:", fileInfo.Name())
22    fmt.Println("Size in bytes:", fileInfo.Size())
23    fmt.Println("Permissions:", fileInfo.Mode())
24    fmt.Println("Last modified:", fileInfo.ModTime())
25    fmt.Println("Is Directory: ", fileInfo.IsDir())
26    fmt.Printf("System interface type: %T\n", fileInfo.Sys())
27    fmt.Printf("System info: %+v\n\n", fileInfo.Sys())
28}
重命名或移动文件
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8func main() {
 9    originalPath := "test.txt"
10    newPath := "test2.txt"
11    err := os.Rename(originalPath, newPath)
12    if err != nil {
13        log.Fatal(err)
14    }
15}
删除文件
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8func main() {
 9    err := os.Remove("test.txt")
10    if err != nil {
11        log.Fatal(err)
12    }
13}
打开或关闭文件
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8func main() {
 9    // Simple read only open. We will cover actually reading
10    // and writing to files in examples further down the page
11    file, err := os.Open("test.txt")
12    if err != nil {
13        log.Fatal(err)
14    }
15    file.Close()
16
17    // OpenFile with more options. Last param is the permission mode
18    // Second param is the attributes when opening
19    file, err = os.OpenFile("test.txt", os.O_APPEND, 0666)
20    if err != nil {
21        log.Fatal(err)
22    }
23    file.Close()
24
25    // Use these attributes individually or combined
26    // with an OR for second arg of OpenFile()
27    // e.g. os.O_CREATE|os.O_APPEND
28    // or os.O_CREATE|os.O_TRUNC|os.O_WRONLY
29
30    // os.O_RDONLY // Read only
31    // os.O_WRONLY // Write only
32    // os.O_RDWR // Read and write
33    // os.O_APPEND // Append to end of file 附加到文件末尾
34    // os.O_CREATE // Create is none exist
35    // os.O_TRUNC // Truncate file when opening 打开时截断文件
36}
检查文件是否存在
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8var (
 9    fileInfo *os.FileInfo
10    err      error
11)
12
13func main() {
14    // Stat returns file info. It will return
15    // an error if there is no file.
16    fileInfo, err := os.Stat("test.txt")
17    if err != nil {
18        if os.IsNotExist(err) {
19            log.Fatal("File does not exist.")
20        }
21    }
22    log.Println("File does exist. File information:")
23    log.Println(fileInfo)
24}

检查读取和写入权限

 1package main
 2
 3import (
 4    "log"
 5    "os"
 6)
 7
 8func main() {
 9    // Test write permissions. It is possible the file
10    // does not exist and that will return a different
11    // error that can be checked with os.IsNotExist(err)
12    file, err := os.OpenFile("test.txt", os.O_WRONLY, 0666)
13    if err != nil {
14        if os.IsPermission(err) {
15            log.Println("Error: Write permission denied.")
16        }
17    }
18    file.Close()
19
20    // Test read permissions
21    file, err = os.OpenFile("test.txt", os.O_RDONLY, 0666)
22    if err != nil {
23        if os.IsPermission(err) {
24            log.Println("Error: Read permission denied.")
25        }
26    }
27    file.Close()
28}
更改权限,所有权和时间戳
 1package main
 2
 3import (
 4    "log"
 5    "os"
 6    "time"
 7)
 8
 9func main() {
10    // Change perrmissions using Linux style
11    err := os.Chmod("test.txt", 0777)
12    if err != nil {
13        log.Println(err)
14    }
15
16    // Change ownership
17    err = os.Chown("test.txt", os.Getuid(), os.Getgid())
18    if err != nil {
19        log.Println(err)
20    }
21
22    // Change timestamps
23    twoDaysFromNow := time.Now().Add(48 * time.Hour)
24    lastAccessTime := twoDaysFromNow
25    lastModifyTime := twoDaysFromNow
26    err = os.Chtimes("test.txt", lastAccessTime, lastModifyTime)
27    if err != nil {
28        log.Println(err)
29    }
30}
硬链接和符号链接

典型的文件只是指向硬盘上称为inode的位置的指针。 硬链接会创建指向同一位置的新指针。 删除所有链接后,才会从磁盘上删除文件。 硬链接仅适用于同一文件系统。 硬链接是您可能认为的“正常”链接。

符号链接或软链接略有不同,它并不直接指向磁盘上的某个位置。 符号链接仅按名称引用其他文件。 它们可以指向不同文件系统上的文件。 并非所有系统都支持符号链接。

 1package main
 2
 3import (
 4    "os"
 5    "log"
 6    "fmt"
 7)
 8
 9func main() {
10    // Create a hard link 硬链接
11    // You will have two file names that point to the same contents
12    // Changing the contents of one will change the other
13    // Deleting/renaming one will not affect the other
14    err := os.Link("original.txt", "original_also.txt")
15    if err != nil {
16        log.Fatal(err)
17    }
18
19	fmt.Println("creating sym")
20    // Create a symlink 符号链接
21    err = os.Symlink("original.txt", "original_sym.txt")
22    if err != nil {
23        log.Fatal(err)
24    }
25
26    // Lstat will return file info, but if it is actually
27    // a symlink, it will return info about the symlink.
28    // It will not follow the link and give information
29    // about the real file
30    // Symlinks do not work in Windows
31    fileInfo, err := os.Lstat("original_sym.txt")
32    if err != nil {
33        log.Fatal(err)
34    }
35    fmt.Printf("Link info: %+v", fileInfo)
36
37    // Change ownership of a symlink only 
38    // and not the file it points to
39    err = os.Lchown("original_sym.txt", os.Getuid(), os.Getgid())
40    if err != nil {
41        log.Fatal(err)
42    }
43}
复制文件
 1package main
 2
 3import (
 4    "os"
 5    "log"
 6    "io"
 7)
 8
 9// Copy a file
10func main() {
11    // Open original file
12    originalFile, err := os.Open("test.txt")
13    if err != nil {
14        log.Fatal(err)
15    }
16    defer originalFile.Close()
17
18    // Create new file
19    newFile, err := os.Create("test_copy.txt")
20    if err != nil {
21        log.Fatal(err)
22    }
23    defer newFile.Close()
24
25    // Copy the bytes to destination from source
26    bytesWritten, err := io.Copy(newFile, originalFile)
27    if err != nil {
28        log.Fatal(err)
29    }
30    log.Printf("Copied %d bytes.", bytesWritten)
31    
32    // Commit the file contents
33    // Flushes memory to disk
34    err = newFile.Sync()
35    if err != nil {
36        log.Fatal(err)
37    }
38}
在文件中寻找位置
 1package main
 2
 3import (
 4    "os"
 5    "fmt"
 6    "log"
 7)
 8
 9func main() {
10    file, _ := os.Open("test.txt")
11    defer file.Close()
12
13    // Offset is how many bytes to move
14    // Offset can be positive or negative
15    var offset int64 = 5
16
17    // Whence is the point of reference for offset
18    // 0 = Beginning of file
19    // 1 = Current position
20    // 2 = End of file
21    var whence int = 0
22    newPosition, err := file.Seek(offset, whence)
23    if err != nil {
24        log.Fatal(err)
25    }
26    fmt.Println("Just moved to 5:", newPosition)
27
28    // Go back 2 bytes from current position
29    newPosition, err = file.Seek(-2, 1)
30    if err != nil {
31        log.Fatal(err)
32    }
33    fmt.Println("Just moved back two:", newPosition)
34
35    // Find the current position by getting the
36    // return value from Seek after moving 0 bytes
37    currentPosition, err := file.Seek(0, 1)
38    fmt.Println("Current position:", currentPosition)
39
40    // Go to beginning of file
41    newPosition, err = file.Seek(0, 0)
42    if err != nil {
43        log.Fatal(err)
44    }
45    fmt.Println("Position after seeking 0,0:", newPosition)
46}
将字节写入文件

您可以只使用打开文件所需的os包进行编写。 由于所有Go可执行文件都是静态链接的二进制文件,因此导入的每个程序包都会增加可执行文件的大小。 诸如io,ioutil和bufio之类的其他软件包提供了更多帮助,但不是必需的。

 1package main
 2
 3import (
 4    "os"
 5    "log"
 6)
 7
 8func main() {
 9    // Open a new file for writing only
10    file, err := os.OpenFile(
11        "test.txt",
12        os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
13        0666,
14    )
15    if err != nil {
16        log.Fatal(err)
17    }
18    defer file.Close()
19
20    // Write bytes to file
21    byteSlice := []byte("Bytes!\n")
22    bytesWritten, err := file.Write(byteSlice)
23    if err != nil {
24        log.Fatal(err)
25    }
26    log.Printf("Wrote %d bytes.\n", bytesWritten)
27}
快速写入文件

ioutil包有一个名为WriteFile()的有用函数,它将处理创建/打开、写入一个字节片段和关闭。如果您只需要一种快速的方法将一段字节转储到一个文件中,那么它非常有用。

 1package main
 2
 3import (
 4    "io/ioutil"
 5    "log"
 6)
 7
 8func main() {
 9    err := ioutil.WriteFile("test.txt", []byte("Hi\n"), 0666)
10    if err != nil {
11        log.Fatal(err)
12    }
13}

参考文章