[TOC]
Go 语言文件操作
本章将主要介绍使用Go语言进行文件的读写相关操作。
Q: 什么是文件?
计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件。
0x00 基本操作
1.文件打开与关闭
描述: 我们可以采用os包中的Open()函数打开一个文件,返回一个*File
和一个err
。然后对得到的文件实例调用Close()
函数就能够关闭文件。
示例演示
[TOC]
本章将主要介绍使用Go语言进行文件的读写相关操作。
Q: 什么是文件?
计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件。
描述: 我们可以采用os包中的Open()函数打开一个文件,返回一个*File
和一个err
。然后对得到的文件实例调用Close()
函数就能够关闭文件。
示例演示
[TOC]
本章将主要介绍使用Go语言进行文件的读写相关操作。
Q: 什么是文件?
计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件。
描述: 我们可以采用os包中的Open()函数打开一个文件,返回一个*File
和一个err
。然后对得到的文件实例调用Close()
函数就能够关闭文件。
示例演示
1 | package main |
执行结果: Type : *os.File, Pointer address: 0xc00000e028, Size of 8
Tips:为了防止文件忘记关闭,我们通常使用defer注册文件关闭语句。
描述: 我们可以多同种方式实现文件读取。
方式1.file.Read()
方法定义如下, 它接收一个字节切片,返回读取的字节数和可能的具体错误,读到文件末尾时会返回0
和io.EOF
。 举个例子:1
func (f *File) Read(b []byte) (n int, err error)
方式2.使用bufio
包NewReader
方法进行行文件读取,它是在file的基础上封装了一层API,支持更多的功能。
1 | func (b *Reader) ReadString(delim byte) (string, error) { |
方式3.使用io/ioutil
包ReadFile
方法读取整个文件, 其只需要将文件名作为参数传入。
1 | func ReadFile(filename string) ([]byte, error) { |
示例1.基础使用
1 | func demo2() { |
执行结果:
1 | 读取类型 []uint8,共读取了 72 字节数据,读取的内容: GoLang - 一门非常Nice的语言! |
示例2.使用for循环读取文件中的所有数据。
1 | func demo3() { |
执行结果:
1 | #END-文件已读完--- |
示例3.bufio读取文件
1 | func demo4() { |
执行结果:
1 | 第1行 - GoLang - 一门非常Nice的语言! |
示例4.ioutil读取整个文件
1 | func demo5() { |
执行结果:
1 | 整文读取: |
描述: 我们可以使用os.OpenFile()
函数能够以指定模式打开文件,从而实现文件写入相关功能。
语法示例:1
2
3func OpenFile(name string, flag int, perm FileMode) (*File, error) {
...
}
参数解析:
1 | os.O_WRONLY #只写 |
r(读)04,w(写)02,x(执行)01
,主要在Linux系统上需要进行设置。文件写入方式
针对于文件的写入我们可以采用如下几种方法。
方法1.Write() 写入字节切片数据
1 | func (f *File) Write(b []byte) (n int, err error) {} |
方法2.WriteString() 写入字符串数据,可以看到其底层还是调用的Write方法,将字符串强转为字节切片。
1 | func (f *File) WriteString(s string) (n int, err error) { |
方法3.bufio.NewWriter() 返回一个文件句柄指针,我可以向该句柄的临时空间进行写入字符串,最后刷新缓存将其中数据写入到文件之中。
1 | // NewWriter returns a new Writer whose buffer has the default size. |
方法4.ioutil.WriteFile() - 写入字符串数据
示例0.利用Fprintf进行字符串写入
1 | func demo0() { |
执行结果:1
2
3
4
5
6DAP server listening at: 127.0.0.1:39039
向标准输出写入内容
➜ demo2 ls -alh Fprint.txt && cat Fprint.txt
-rw-r--r-- 1 weiyigeek weiyigeek 110 9月 17 01:40 Fprint.txt
2.我是写入的字符串: 我喜爱网络安全技术
1.我是写入的字符串:我喜爱网络安全技术%
示例1.写入字符切片或者字符串1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18func demo1() {
// 1.打开需要写的文件,如果文件不存在就创建并晴空内容,对于该文件只写,其权限为0644.
file, err := os.OpenFile("write.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Open write file error:", err)
return
}
defer file.Close()
// 2.方式1以字节切片数据写入。
var str0 = []byte{'a', 'b', 'c', ' '}
str0 = append(str0, 'o', 'p', 'f', '\n')
file.Write(str0)
// 3.方式2以字符串数据写入。
var str1 string = "Hello , Go - 我是要写入的字符串。"
file.WriteString(str1)
}
执行结果:1
2
3
4➜ demo2 ls -alh write.txt && cat write.txt
-rw-r--r-- 1 weiyigeek weiyigeek 51 9月 16 09:05 write.txt
abc opf
Hello , Go - 我是要写入的字符串。%
示例2.利用bufio.NewWriter()方法写入字符串。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19func demo2() {
// 1.打开需要写的文件,如果文件不存在就创建并晴空内容,对于该文件只写,其权限为0644.
file, err := os.OpenFile("write.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Open write file error:", err)
return
}
defer file.Close()
// 2.实例化得到一个文件句柄的缓冲区
writer := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
// 3.将数据先写入缓存
line := fmt.Sprintf("第%d行,hello go,bufio.NewWriter 写入!\n", i+1)
writer.WriteString(line)
}
// 4.将缓存中的内容写入文件
writer.Flush()
}
执行结果:1
2
3
4
5
6
7
8
9
10
11
12➜ demo2 ls -alh write.txt && cat write.txt
-rw-r--r-- 1 weiyigeek weiyigeek 451 9月 16 09:37 write.txt
第1行,hello go,bufio.NewWriter 写入!
第2行,hello go,bufio.NewWriter 写入!
第3行,hello go,bufio.NewWriter 写入!
第4行,hello go,bufio.NewWriter 写入!
第5行,hello go,bufio.NewWriter 写入!
第6行,hello go,bufio.NewWriter 写入!
第7行,hello go,bufio.NewWriter 写入!
第8行,hello go,bufio.NewWriter 写入!
第9行,hello go,bufio.NewWriter 写入!
第10行,hello go,bufio.NewWriter 写入!
示例3.从终端中输入信息并写入到文件之中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23func demo3() {
var msg0, msg1, msg string
// 方式1.终端获取字符串(以空格和换行结束)
fmt.Println("# 请输入你要向文件写入的字符串:")
fmt.Scanln(&msg0)
// 方式2.采用NewReader获取终端输入(以指定字符为截止符)
fmt.Print("# 请输入你要向文件写入的字符串:")
reader := bufio.NewReader(os.Stdin)
msg1, _ = reader.ReadString('\n')
// 字符串拼接(推荐方式)
var build strings.Builder
build.WriteString(msg0)
build.WriteString(msg1)
msg = build.String()
err := ioutil.WriteFile("./WriteFile.txt", []byte(msg), 0644)
if err != nil {
fmt.Println("open file faild:", err)
return
}
}
执行结果:1
2
3
4
5
6
7➜ demo2 go run filewrite.go
# 请输入你要向文件写入的字符串:
WeiyiGeek
# 请输入你要向文件写入的字符串:This is a string
➜ demo2 ls -alh WriteFile.txt && cat WriteFile.txt
-rw-r--r-- 1 weiyigeek weiyigeek 26 9月 17 02:14 WriteFile.txt
WeiyiGeekThis is a string
(1) 实现一个类似cat命令
使用文件操作相关知识,模拟实现linux平台cat命令的功能。1
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
46package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
)
// cat命令实现函数
func cat(r *bufio.Reader) {
for {
// 注意是字符,按照每行进行读取
buf, err := r.ReadBytes('\n')
if err == io.EOF {
// 退出之前将已读到的内容输出
fmt.Fprintf(os.Stdout, "%s", buf)
break
}
fmt.Fprintf(os.Stdout, "%s", buf)
}
}
func main() {
// 解析命令行参数
flag.Parse()
// 如果没有参数默认从标准输入读取内容
if flag.NArg() == 0 {
fmt.Printf("未指定文件将从标准输入读取内容:")
stdin := bufio.NewReader(os.Stdin)
// 以换行符为结束
buf, _ := stdin.ReadBytes('\n')
// 将终端输入字符串向终端输出
fmt.Fprintf(os.Stdout, "\n%s", buf)
}
// 依次读取每个指定文件(可多个文件)的内容并打印到终端
for i := 0; i < flag.NArg(); i++ {
f, err := os.Open(flag.Arg(i))
if err != nil {
fmt.Fprintf(os.Stdout, "reading from %s failed, err:%v\n", flag.Arg(i), err)
continue
}
cat(bufio.NewReader(f))
}
}
执行结果:1
2
3
4
5
6
7
8
9➜ demo3 hostname > {1..6}.txt
➜ demo3 go build -o cat
➜ demo3 ./cat
未指定文件将从标准输入读取内容:This is os.stdio My name is WeiyiGeek
This is os.stdio My name is WeiyiGeek
➜ demo3 ./cat 1.txt 2.txt 3.txt
ubuntu-pc
ubuntu-pc
ubuntu-pc
(1) 实现文件的拷贝
描述: 我们可以借助io.Copy()
实现一个拷贝文件函数。1
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
44package main
import (
"flag"
"fmt"
"io"
"os"
)
// CopyFile 拷贝文件函数
func CopyFile(srcName, dstName string) (written int64, err error) {
// 以读方式打开源文件
src, err := os.Open(srcName)
if err != nil {
fmt.Printf("open %s failed, err:%v.\n", srcName, err)
return
}
defer src.Close()
// 以写|创建的方式打开目标文件
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Printf("open %s failed, err:%v.\n", dstName, err)
return
}
defer dst.Close()
return io.Copy(dst, src) //调用io.Copy()拷贝内容
}
func main() {
// 解析命令行参数
flag.Parse()
// 如果没有传递两个参数则显示使用说明
if flag.NArg() != 2 {
fmt.Println("Usage: ./copy src.file dst.file")
return
}
// 从命令行中获取要操作的文件
fmt.Printf("正在复制从 %s 文件内容,到目标文件 %s 中.....", flag.Arg(0), flag.Arg(1))
_, err := CopyFile(flag.Arg(0), flag.Arg(1))
if err != nil {
fmt.Println("copy file failed, err:", err)
return
}
fmt.Println("copy done!")
}
执行结果:1
2
3
4
5
6
7
8echo "Hello Weiyigeek, 你喜欢做什么" > hello.txt
➜ demo4 go build -o copy
➜ demo4 ./copy
Usage: ./copy src.file dst.file
➜ demo4 ./copy hello.txt copyhello.txt
正在复制从 hello.txt 文件内容,到目标文件 copyhello.txt 中.....copy done!
➜ demo4 cat copyhello.txt
Hello Weiyigeek, 你喜欢做什么
(1) 文件内容定位读取
描述:我们可以利用官方提供的os标准库中的type File struct{}
结构体中的func (*File) Seek
方法来进行,文件内容定位和光标插入等操作。
语法说明:1
2
3// Seek设置下一次读/写的位置,它返回新的偏移量(相对开头)和可能的错误。
func (f *File) Seek(offset int64, whence int) (ret int64, err error)
offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。
例如,文本文件 tmp.txt 其内容为如下,我们想对其weiyi后插入指定字符并对源文件进行覆盖:1
2
3
4tee tmp.txt <<'EOF'
weiyihobby
computer
EOF
代码演示:1
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65package main
import (
"fmt"
"io"
"os"
)
func testInsert() {
// 源文件
file, err := os.OpenFile("./tmp.txt", os.O_RDONLY, 0644)
if err != nil {
fmt.Printf("Open tmp.txt file failed, err: %v", err)
return
}
// 临时文件
filetmp, err := os.OpenFile("./tmp.tmp", os.O_CREATE|os.O_TRUNC|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Open tmp.tmp file failed, err: %v", err)
return
}
// 光标的开始位置
file.Seek(0, 0)
// 读取光标后的五个字符
var ret [5]byte
n, err := file.Read(ret[:]) // weiyigeek
if err != nil {
fmt.Printf("file.Read failed, err: %v", err)
return
}
fmt.Printf("# read %d character: %s", n, ret[:n])
filetmp.Write(ret[:n])
// 写入要插入的字符串。
str := "Geek"
filetmp.WriteString(str)
// 将剩下的字符串读取并写入到临时文件中
var tmp [128]byte
for {
n, err := file.Read(tmp[:]) //每次读128Byte存入tmp中并返回字节数
if err == io.EOF {
filetmp.Write(tmp[:n])
break
} else if err != nil {
fmt.Println("read file failed, err:", err)
return
}
filetmp.Write(tmp[:n])
}
// 将临时文件重命名
os.Rename("./tmp.tmp", "./tmp.txt")
// 关闭源文件
defer file.Close()
defer filetmp.Close()
}
func main() {
fmt.Println("# 指定文件内容插入演示")
testInsert()
}
执行结果:1
2
3
4
5# 指定文件内容插入演示
# read 5 character: weiyi
$cat tmp.txt
weiyiGeekhobby
computer
你好看友,欢迎关注博主微信公众号哟! ❤
这将是我持续更新文章的动力源泉,谢谢支持!(๑′ᴗ‵๑)
温馨提示: 未解锁的用户不能粘贴复制文章内容哟!
方式1.请访问本博主的B站【WeiyiGeek】首页关注UP主,
将自动随机获取解锁验证码。
Method 2.Please visit 【My Twitter】. There is an article verification code in the homepage.
方式3.扫一扫下方二维码,关注本站官方公众号
回复:验证码
将获取解锁(有效期7天)本站所有技术文章哟!
@WeiyiGeek - 为了能到远方,脚下的每一步都不能少
欢迎各位志同道合的朋友一起学习交流,如文章有误请在下方留下您宝贵的经验知识,个人邮箱地址【master#weiyigeek.top】
或者个人公众号【WeiyiGeek】
联系我。
更多文章来源于【WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少】, 个人首页地址( https://weiyigeek.top )
专栏书写不易,如果您觉得这个专栏还不错的,请给这篇专栏 【点个赞、投个币、收个藏、关个注、转个发、赞个助】,这将对我的肯定,我将持续整理发布更多优质原创文章!。
最后更新时间:
文章原始路径:_posts/编程世界/Go/Package/3.Go语言之文件操作学习记录.md
转载注明出处,原文地址:https://blog.weiyigeek.top/2020/4-23-728.html
本站文章内容遵循 知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议