Go语言学习笔记(二十一)
一、处理文件
1 文件的重要性
- 文件是硬盘中的数据,它可以让我们管理配置、存储程序的状态乃指从底层操作系统中读取数据
- UNIX(Linux和macOS)的一个重要的特征是,将一切都视为文件。这意味着在操作系统看来,从键盘到打印机的所用东西都可像文件那样编址。在这方面,UNIX走的更远,他通过虚拟文件系统来暴露系统信息。这意味着可像读取文件一样读取系统数据。
- 在UNIX系统中,可使用命令cat来读取文件的内容并将其打印到终端。鉴于UNIX系统以文件的方式暴露系统数据,因此命令cat也可用来提取有关底层系统的信息。/proc/loadavg就是这样的一个虚拟文件,它包含有关系统当前负载的信息。
因为我用的是Windows 10所以没有相关运行结果。
2 使用ioutil包读取文件
2.1 读取文件
使用函数:
Readfile()
以一个文件名为参数,将文件的内容转变为字节切片的数据并返回
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
fileBytes, err := ioutil.ReadFile("example01.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(fileBytes)
fileString := string(fileBytes)
fmt.Println(fileString)
}

2.2 创建文件
- 使用函数
WriteFile- 可以使用这个函数创建文件向文件中写入数据。
- 函数参数为文件名、要写入的数据以及应用于文件的权限
- 文件的权限是从UNIX权限衍生出来的,他们对应于三类用户:文件所有者、与文件位于同一组的用户、其他用户。
- Go语言使用UNIX权限的数字表示法,很多用于处理文件的函数都将权限值作为参数。下表说明了数字表示法和符号表示法

符号表示法是数字表示法的视觉表示。符号表示法总共包含10个字符。最左边的字符指出了文件是普通文件、目录还是其他东西,如果这个字符为-,就表示文件为普通文件;接下来的3个字符指定了文件所有者的权限;在接下来的3个字符表示所有者所在用户组的权限;而最后三个字符表示其他人的权限。
从上表可知,数字0777表示所有人都有所有的权限,而相应的符号表示法没有确实任何字符;相反,数字权限0700表示只有所有者才能对文件执行任何操作。
在UNIX型系统中,文件的默认权限为0644,即所有者能够都区和谐如,而其他人只能读取。在文件系统中创建文件时。应如何考虑给他制定权限。如果不确定该如何指定权限,使用默认的UNIX权限就好了
package main
import (
"io/ioutil"
"log"
)
func main() {
b := make([]byte, 0)
err := ioutil.WriteFile("example02.txt", b, 0644)
if err != nil {
log.Fatal(err)
}
}
Windows Powershell下显示的结果是这样的。

3 写入文件
函数WriteFile也可用来写入文件。向文件中写入数据,只要将函数的第二个参数换成我们想要写入的数据即可。但是这里要注意,我们传入的参数一定是字节切片类型的。程序示例如下:
package main
import (
"io/ioutil"
"log"
)
func main() {
s := "Hello World"
err := ioutil.WriteFile("example03.txt", []byte(s), 0644)
if err != nil {
log.Fatal(err)
}
}
这里传入了一个空的字节切片
4 列出目录的内容
要处理文件系统中的文件,必须知道目录结构。为此,ioutil包提供了便利函数ReadDir,他接受以字符串方式指定的目录名,并返回一个列表,其中包含按文件名排序的文件。文件名的类型为FileInfo,包含如下信息。
Name:文件的名称
Size:文件的长度,单位字节
Mode:用二进制位表示的权限
ModTime:文件最后一个被修改的时间。
IsDir:文件是否为目录
Sys:底层数据源
程序示例如下:
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
files, err := ioutil.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Mode(), file.Name())
}
}
运行结果如下:

5 复制文件
ioutil包可用于执行一些常见的文件处理操作,但要执行更复杂的操作,应使用os包。os包运行在稍低的层级,因此使用它时,必须手动关闭打开的文件。如果阅读os包的源代码,将发现ioutil包中的很多函数都是os包包装器,我们无须显式地地关闭文件。
要复制文件,只需结合使用os包中的几个函数。以编程方式复制文件的步骤如下。
1. 打开要复制的文件
2. 读取其内容
3.创建并打开要将这些内容复制到其中的文件
4. 将内容写进这个文件
5. 关闭所有已打开的文件
程序示例如下:
package main
import (
"io"
"log"
"os"
)
func main() {
from, err := os.Open("./example05.txt")
if err != nil {
log.Fatal(err)
}
defer from.Close()
to, err := os.OpenFile("./example05.copy.txt", os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
log.Fatal(err)
}
defer to.Close()
_, err = io.Copy(to, from)
if err != nil {
log.Fatal(err)
}
}
- 使用os包中的函数Open来读取磁盘文件
- 使用defer语句在程序完成其他所有操作后关闭文件
- 使用OpenFile函数打开文件。第一个参数是要打开(如果不存在,就创建)的文件的名称;第二个参数是用于文件的标志,在这里指定的是读写文件,并在文件不存在时创建它;最后一个参数设置文件的权限
- 再次使用defer语句在执行完其他操作后关闭文件
- 使用io包中的函数Copy复制源文件中的内容,并将其写入目标文件。
6 删除文件
为了删除文件,os包提供了函数Remove,但是要注意的是这个函数被使用时不会发出警告,我们也无法将要删除的文件恢复,因此务必小心。
实例程序如下:
package main
import (
"log"
"os"
)
func main() {
err := os.Remove("./deleteme.txt")
if err != nil {
log.Fatal(err)
}
}
7 使用文件来管理配置
在编程中常使用文件来管理配置。考虑到代码可能在不同的环境中执行,可使用一个文件来设置各种用于启动程序的配置参数。在开发过程中,应用程序将从开发环境移到生存环境中,而使用文件是管理环境差异的有效方式。这种环境差别包括如下几个方面。
- Web服务的URL
- 访问密钥
- 端口号
- 环境变量
7.1 使用JSON文件
在声明可存储在文件中并在必要时读取的配置方面,JSON是一种卓有成效的标准方式。将配置存储在文件中的另一个优点是,可对其进行版本控制并集成到自动构建过程中。JSON是一种声明键值的简单方式,我们可以将这些键值解码为Go结构体,在使用它们。
通过将配置存储在JSON文件中,Go程序可读取这个文件,并将其作为配置数据使用。程序示例如下:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
)
type Config struct {
Name string `json:"name"`
Awake bool `json:"awake"`
Hungry bool `json:"hungry"`
}
func main() {
f, err := ioutil.ReadFile("config.json")
if err != nil {
log.Fatal(err)
}
c := Config{}
err = json.Unmarshal(f, &c)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", c)
}
7.2 使用TOML文件
TOML(Tom’s Obvious, Minimal Language)是一种专门为存储配置文件而设计的格式。JSON是为了序列化数据而设计的,因此TOML相比较于JSON有一定的优势,它更容易阅读。具备JSON没有的特性(如注释)。在基本层面,TOML的语法非常简单,可像JSON那样指定键和值。
Name = "George"
Awake = true
Hungry = false
TOML和JSON一样不是Go的组成部分,它可用于任何语言。Go的标准库中没有支持TOML的包,所以我们要使用第三方包。安装如下
go get github.com/BurntSushi/toml
这个包提供了函数DecodeFile,这个函数接收一个文件名以及一个要将TOML解码到其中的结构体。示例程序如下:
import (
"fmt"
"log"
"github.com/BurntSushi/toml"
)
type Config struct {
Name string
Awake bool
Hungry bool
}
func main() {
c := Config{}
_, err := toml.DecodeFile("config.toml", &c)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", c)
}
8 相关问答
8.1 ioutil包为何没有提供用于执行复制文件等操作的函数?
Go语言致力于确保核心库小乔而轻量级的。另外,不同的操作系统差别很大,这导致创建通用的文件赋值方法是很难的。鉴于此,没有用于赋值文件的便利方法,要复制文件,应使用os包。
8.2 操作文件前,Go语言是否会核实文件确实存在?
不会,程序员必须在使用文件前核实他确实存在。如果文件不存在,将引发错误。
8.3 如何确定该给文件设置什么样的权限?
如果不确定该给文件设置什么样的权限,应采取保守的态度,设置尽可能低的权限,默认的UNIX权限0644就是不错的选择。设置过于宽松的权限(如0777)意味着如果服务器被攻破,则攻击者将能够随意处置文件,包括将其删除。
8.4 如果操作系统中的文件权限被设置为权限0700,Go语言程序能够读取它么?
Go程序在用户的上下文中执行。权限为0700的文件只有所有者才能使用,如果执行Go程序的用户就是文件的所有者,则程序能够读取这个文件;否则程序将不能访问它。
8.5 相比于JSON,使用TOML有哪些优点?
TOML是一种专门为存储配置文件而设计的数据格式,因此支持在文件中包含注释,这有助于提高配置文件的可读性和可维护性。使用TOML格式时,也更容易表示Go数据类型。
参考书籍
[1]: 【Go语言入门经典】[英] 乔治·奥尔波 著 张海燕 译
本文详细介绍了Go语言中处理文件的各种方法,包括使用ioutil包读取和写入文件,创建、复制、删除文件,以及通过JSON和TOML管理配置。还探讨了文件权限、目录操作和相关问题,强调了Go语言在文件操作中的注意事项和最佳实践。
383

被折叠的 条评论
为什么被折叠?



