# Go语言文件操作
# 1 文件的概念
文件是数据源(保存数据的地方)的一种,比如大家经常使用的word文档,txt文档,excel文件…都是文件。文件最主要的作用就是保存数据,它既可以保存一张图片,也可以保存视频,声音………
# 2 输入流和输出流
文件在程序是以流的形式操作的, 在Python,JAVA,Go ... 都一样;
# 3 打开和关闭文件
要想操作文件,有两个关键的概念,就是打开文件和关闭文件。 os包下有一个Open函数,如下:
//Open打开指定的文件进行读取。如果成功,可以使用返回File对象的方法进行读取;
//关联的文件描述符只有O_RDONLY模式。如果出现错误,则类型为*PathError。
//Open()函数返回的是一个 *File 文件类型的指针,和一个error。
func Open(name string) (*File, error)
2
3
4
//Close关闭文件,使其不能用于I/O。如果有错误,则返回一个。
func (f *File) Close() error
2
# 3.1 简单举例
package main
import (
"fmt"
"os"
)
func main(){
//这里的file 有人叫对象,有人叫指针,有人叫句柄,无所谓--心态,哈哈
//打开文件
file, err := os.Open("D:/test.txt")
if err!=nil{
fmt.Println(err)
}
//这里简单打印下这个file,没有任何操作,现在是个指针而已
fmt.Printf("file=%v",file)
e:= file.Close()//关闭文件
if e!=nil {
fmt.Println(e)
}
}
//输出结果
file=&{0xc000090780}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 4 读取文件
go语言读取文件有很多种方式,基本上在标准库的
os
包,io/ioutil
包以及bufio
包,比如下面几种
- 1、os包下的Open()和Read()
- 2、bufio包下的带缓冲的读取
- 3、ioutil包下的读取
# 4.1 OS包下的Open()和Read()
os包提供了平台无关的操作系统功能接口。 里面的File 的各种方法也是可以获取文件相关信息,具体的可以看api。 比如读取文件,我们就可以用 Open() 和Read()方法
D:/test.txt
内容如下图
//从文件中读取到len(b)字节。它返回读取的字节数和遇到的任何错误。
//读取到文件末尾,Read返回0 io.EOF。
func (f *File) Read(b []byte) (n int, err error)
2
3
# os包下的Read()举例
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 只读方式打开当前目录下的main.go文件
file, err := os.Open("D:/test.txt")
if err != nil {
fmt.Println("打开文件异常, err:", err)
return
}
defer file.Close() //退出时关闭
// 使用Read方法读取数据
var tmp = make([]byte, 128)
n, err := file.Read(tmp)
if err == io.EOF {
fmt.Println("文件读完了")
return
}
if err != nil {
fmt.Println("读取文件错误, err:", err)
return
}
fmt.Printf("读取了%d字节数据\n", n)
fmt.Println(string(tmp[:n]))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 输出结果如下
读取了55字节数据
the first data
two Hello 中国
three world 成都
2
3
4
# 4.2 bufio-带缓冲区的方式读取
bufio是在file的基础上封装了一层API,支持更多的功能。
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main(){
//打开文件
file, err := os.Open("D:/test.txt")
if err!=nil{
fmt.Println(err)
}
defer file.Close() //函数退出时关闭file对象
//创建一个*Reader ,带缓冲区,注意默认是4096
reader:=bufio.NewReader(file)
//循环读取
for{
line,err:=reader.ReadString('\n')//读到换行就结束
fmt.Print(line)
if err==io.EOF{
if len(line) != 0 {
fmt.Println(line)
}
fmt.Println("文件读完了")
break
}
if err != nil {
fmt.Println("读取文件错误, err:", err)
return
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 4.3 ioutil 包下的读取
更多ioutil说明请看ioutil-API
ioutil包下的函数
- func NopCloser(r io.Reader) io.ReadCloser //其实就是个转换工具
- func ReadAll(r io.Reader) ([]byte, error) //从io.Reader中一次读取所有数据
- func ReadDir(dirname string) ([]os.FileInfo, error)//读取目录并返回排好序的文件和子目录名
- func ReadFile(filename string) ([]byte, error) //ReadFile 读取整个文件的内容
- func TempDir(dir, prefix string) (name string, err error) //临时目录
- func TempFile(dir, pattern string) (f *os.File, err error) //临时文件
- func WriteFile(filename string, data []byte, perm os.FileMode) error
2
3
4
5
6
7
# 注意点
ReadFile
不需要写Close()
内部已经封装了。而ReadAll()
好像内部没写,我反正没找到。所以,这个不同一定要注意。
# ioutil读取文件举例
package main
import (
"fmt"
"io/ioutil"
)
// ioutil.ReadFile读取整个文件
func main() {
content, err := ioutil.ReadFile("D:/test.txt")
if err != nil {
fmt.Println("读取文件错误, err:", err)
return
}
fmt.Println(string(content))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 5 写文件操作应用实例
- 1、os 包下的Read 和Write
- 2、bufio包下的writer,bufio.NewWriter
- 3、ioutil 下的WriteFile
# 5.1 os包下的写文件
os.OpenFile()
函数能够以指定模式打开文件,从而实现文件写入相关功能。
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
...
}
2
3
name:要打开的文件名 flag:打开文件的模式。perm:文件权限,一个八进制数。r(读)04,w(写)02,x(执行)01。 打开文件的模式有以下几种:
模式 | 含义 |
---|---|
os.O_WRONLY | 只写 |
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
# 举例
package main
import (
"fmt"
"os"
)
func main() {
filePath := "D:/new.txt"
//打开文件,没有就创建一个,在linux 下rw可读可写
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0666)
if err!=nil{
fmt.Println("打开文件失败")
}
defer file.Close()
var str="我是写入的内容"
n, e := file.WriteString(str)
if e != nil {
fmt.Println("写入文件错误", e)
return
}
fmt.Println("写入的字节数是:", n)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 5.2 bufio包下的写文件
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
filePath := "D:/new.txt"
//打开文件,没有就创建一个,在linux 下rw可读可写
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
fmt.Println("打开失败")
}
defer file.Close() //退出时关闭
str := "我是bufio写入内容"
writer := bufio.NewWriter(file)//创建一个Writer
writer.WriteString(str) //将数据写入缓冲区
writer.Flush() //将缓存中的内容写入文件
//因为带缓冲区的writer ,是先将内容写入缓存,然后调用flush方法写入文件中
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 5.3 ioutil下的写文件
//WriteFile 将data写入filename文件中,当文件不存在时会根据perm指定的权限进行创建一个,
//文件存在时会先清空文件内容。对于perm参数,我们一般可以指定为:0666,具体含义os包中讲解。
func WriteFile(filename string, data []byte, perm os.FileMode) error
2
3
# 举例
package main
import (
"fmt"
"io/ioutil"
)
func main() {
filePath1 := "d:/new.txt"
filePath2:="d:/xxx.txt"
//读取文件new.txt的内容准备写入xxx.txt
bytes, e := ioutil.ReadFile(filePath1)
if e!=nil{
fmt.Println("读取文件错误",e)
}
// 写入文件内容
err := ioutil.WriteFile(filePath2, bytes, 0666)
if err != nil {
fmt.Println("写入文件错误, err:", err)
return
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 注意点
ioutil读和写文件就是省事,工具。 但是写文件要注意的是,它没有回自动创建,并且有会清空文件, 所以如果你要往文件中追加内容就不能用writeFile了,所以,如果要追加还是清空,根据需求来
# 6文件编程应用实例
# 6.1 拷贝文件
借助io.Copy()实现一个拷贝文件函数。io.Copy()简要说明如下
//从src复制到dst,直到在src上到达EOF或发生错误。它返回复制的字节数和复制时遇到的第一个错误(如果有的话)。
//成功复制将返回err==nil,而不是err==EOF。因为Copy被定义为从src读取到EOF,所以它不将从read读取的EOF视为要报告的错误。
//如果src实现WriterTo接口,则通过调用src.writeto(dst)实现copy。否则,如果dst实现了ReaderFrom接口,则通过调用dst.readfrom(src)来实现copy。
func Copy(dst Writer, src Reader) (written int64, err error)
2
3
4
package main
import (
"fmt"
"io"
"os"
)
//CopyFile文件函数封装
//参数说明 dstFileName--目标文件路径 srcFileName--源文件路径
// 返回参数说明written--复制成功的字节数,err--复制失败的错误信息
func CopyFile(dstFileName, srcFileName string) (written int64, err error) {
// 以读方式打开源文件
reader, readError := os.Open(srcFileName)
if readError != nil {
fmt.Printf("从 %s 打开文件失败, err:%v.\n", srcFileName, err)
return 0, readError
}
defer reader.Close() //退出时关闭
// 以读写|创建的方式打开目标文件
writer, writerError := os.OpenFile(dstFileName, os.O_RDWR|os.O_CREATE, 0666)
if writerError != nil {
fmt.Printf("从 %s 打开文件失败, err:%v.\n", dstFileName, err)
return 0, writerError
}
defer writer.Close() //退出时关闭
return io.Copy(writer, reader)
}
func main() {
//把srcFile.txt这个文件复制给d:/dstFile.txt
written, err := CopyFile("d:/dstFile.txt", "d:/srcFile.txt")
if err != nil {
fmt.Println("复制文件失败, err:", err)
return
}
fmt.Println("复制成功!")
fmt.Println("复制的字节数", written)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 6.2 统计字符数量
看一个例子:统计一个文件中含有的英文、数字、空格以及其他字符数量
- 实现思路: 打开文件——>逐行读——>记录每一行的统计数量——>得到总的统计
package main
import (
"bufio"
"fmt"
"io"
"os"
)
// CharCount 统计个数的结构体
type CharCount struct {
EnCount int //英文个数
NumCount int //数字个数
SpaceCount int //空格个数
OtherCount int //其他字符
}
func main() {
file, err := os.Open("d:/test.txt")
if err!=nil{
fmt.Println(err)
return
}
defer file.Close()
count:=CharCount{}
reader := bufio.NewReader(file)
for{
s, err := reader.ReadString('\n')
if err==io.EOF{
break
}
str:=[]rune(s)
for _,v:=range str{
switch{
case v>'a'&&v<'z':
fallthrough
case v>'A'&&v<'Z':
count.EnCount++
case v==' '||v=='\t':
count.SpaceCount++
case v>0&&v<9:
count.NumCount++
default:
count.OtherCount++
}
}
}
fmt.Printf(" 英文个数:%d\n 数字个数:%d\n 空格个数:%d\n 其他字符个数:%d\n",count.EnCount,count.NumCount,count.SpaceCount,count.OtherCount)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50