翻译自《Go Programming Cookbook》Aaron Torres - Chapter 1: I/O and Filesystems
当你跨平台时,操作目录和文件是非常困难的 (例如在Windows 和 Linux 上)。Golang 在 os 和 ioutils 包中,对操作文件和目录提供了跨平台支持。我们已经见过使用 ioutils 包的例子,但是现在我们将探索以其他的方式使用这些包。
如何操作
接下来的步骤将涵盖如何编写并运行你的应用:
- 在终端或者命令行应用中,创建一个新的目录:
~/projects/go-programming-cookbook/chapter1/filedirs
- 进入该目录
- 运行一下命令:
$ go mod init github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/filedirs
4.创建名为dirs.go的文件,并包含以下内容:
package filedirs
import (
"errors"
"io"
"os"
)
func Operate() error {
// 这里的0755和在命令行上使用chown是类似的,这会在执行目录的目录下创建example_dir这个目录,这里也可以使用绝对路径而不是相对路径
if err := os.Mkdir("example_dir", os.FileMode(0755)); err != nil {
return err
}
// 进入到example_dir目录下
if err := os.Chdir("example_dir"); err != nil {
return err
}
// f是一个通用文件对象,它实现了多个接口
// 如果在打开文件时,设置了正确的权限位,可以当作 reader 和 writer 使用
f, err := os.Create("test.txt")
if err != nil {
return err
}
// 将一个已知长度的内容写入到文件中,并且验证写入的是否正确
value := []byte("hello")
count, err := f.Write(value)
if err != nil {
return err
}
if count != len(value) {
return errors.New("incorrect length returned from write")
}
if err := f.Close(); err != nil {
return nil
}
// 读文件
f, err = os.Open("test.txt")
if err != nil {
return err
}
io.Copy(os.Stdout, f)
if err := f.Close(); err != nil {
return err
}
// 前往上一级目录
if err := os.Chdir(".."); err != nil {
return err
}
if err := os.RemoveAll("example_dir"); err != nil {
return err
}
return nil
}
- 创建名为files.go的文件,并且包含以下内容:
package filedirs
import (
"bytes"
"io"
"os"
"strings"
)
// 函数 Capitalizer 的作用是打开一个文件,读取其中的内容,然后将该内容写入到另一个文件中
func Capitalizer(f1 *os.File, f2 *os.File) error {
if _, err := f1.Seek(0, io.SeekStart); err != nil {
return nil
}
var tmp = new(bytes.Buffer)
if _, err := io.Copy(tmp, f1); err != nil {
return err
}
s := strings.ToUpper(tmp.String())
if _, err := io.Copy(f2, strings.NewReader(s)); err != nil {
return err
}
return nil
}
// 函数 CapitalizeExample 的作用是创建两个文件,对其中一个文件进行写操作
// 然后调用函数 Capitalizer
func CapitalizeExample() error {
f1, err := os.Create("file1.txt")
if err != nil {
return err
}
if _, err := f1.Write([]byte(`this file contains a
number of words and new lines`)); err != nil {
return err
}
f2, err := os.Create("file2.txt")
if err != nil {
return err
}
if err := Capitalizer(f1, f2); err != nil {
return err
}
if err := os.Remove("file1.txt"); err != nil {
return err
}
if err := os.Remove("file2.txt"); err != nil {
return err
}
return nil
}
- 创建名为example的新目录,并进入目录
- 创建名为main.go的文件,并且包含以下内容:
package main
import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/filedirs"
func main() {
if err := filedirs.Operate(); err != nil {
panic(err)
}
if err := filedirs.CapitalizeExample(); err != nil {
panic(err)
}
}
- 执行以下命令
$ go build
$ ./example
你将会看到以下输出:
hello
程序是如何运行的
如果您熟悉Unix中的文件操作,那么对Go的os库应该会非常熟悉。 您基本上可以执行所有常见操作-- Stat 文件来收集文件的属性,收集具有不同权限的文件,以及创建和修改目录和文件。 在这节中,我们对目录和文件执行了许多操作,然后删除他们。
使用文件对象与使用内存流非常相似。 Files还提供了许多便利的方法,例如Chown,Stat和Truncate。 熟悉文件操作的最简单方法就是使用它们。 在之后章节中,我们都必须在程序执行的最后,再对文件进行清理。
构建后端应用程序时,使用文件是非常常见的操作。 文件可用于配置,密钥,临时存储等。 Go使用os包,包装了系统调用,并且无论您使用Windows还是Unix,都允许执行相同的功能。
一旦打开文件并将其存储在File结构中,就可以轻松地将其传递到许多接口中(我们之前已讨论过这些接口)。 在前面的示例中,都可以直接使用os.File结构体替代缓冲区和内存中的数据流,以便对磁盘上存储的数据进行操作。 这对于某些技术可能很有用,例如,通过单个写入调用将所有日志同时写入stderr和文件中。