Go-IO标准库
Go IO标准库操作
Go 语言中,为了方便开发者使用,将 IO 操作封装在了如下几个包中:
os.FileInfo 为文件信息接口
io 为 IO 原语(I/O primitives)提供基本的接口
- io/ioutil 封装一些实用的 I/O 函数
- fmt 实现格式化 I/O,类似 C 语言中的 printf 和 scanf
- bufio 实现带缓冲I/O
文件信息
接口属性
1 | type FileInfo interface { |
os.fileStat结构体实现了FileInfo接口的所有方法
1 | type fileStat struct { |
文件路径相关函数
路径相关的函数有两个包,path
和 path/filepath
,
两个包内有一些相同的函数,如IsAbs()
、Join()
、Dir()
filepath中的函数兼容各个操作系统,涉及到windows系统路径操作时,应该使用filepath包
filepath.Rel(basepath, targpath string) (string, error)
获取相对路径filepath.Abs(path string) (string, error)
获取绝对路径,如果path不是绝对路径,会加入当前工作目录以使之成为绝对路径。path.Join(elem ...string) string
路径拼接path.IsAbs(path string) bool
判断文件是否是绝对路径path.Dir(path string) string
获取目录
文件的常规操作
创建目录 如果存在则失败
```go
os.Mkdir(name string, perm FileMode) error1
2
3
4
5
6
- 仅创建一层
- 相当于`linux`命令`mkdir`
- ```go
os.MkdirAll(path string, perm FileMode) error- 创建多层
- 相当于
linux
命令mkdir -p
创建文件 如果存在会覆盖
- ```go
os.Create(name string) (file *File, err error)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
- 底层调用 `os.OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)`
- 采用模式`0666`(任何人都可读写,不可执行)
- 如果文件存在会清空它
### 打开文件
* `os.Open(name string) (file *File, err error)`
* 底层调用`OpenFile(name, O_RDONLY, 0)`
* 以只读的方式打开文件
* `os.OpenFile(name string, flag int, perm FileMode) (file *File, err error)`
* perm可为0066、0777等
* flag是os包中定义的常量
```go
const (
O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
O_RDWR int = syscall.O_RDWR // 读写模式打开文件
O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
O_CREATE int = syscall.O_CREAT // 如果不存在将创建一个新文件
O_EXCL int = syscall.O_EXCL // 和O_CREATE配合使用,文件必须不存在
O_SYNC int = syscall.O_SYNC // 打开文件用于同步I/O
O_TRUNC int = syscall.O_TRUNC // 如果可能,打开时清空文件
)
关闭文件
```
file.Close() error1
2
3
4
5
6
7
8
- *File指针的方法
- 程序与文件之间的连接断开
### 删除文件或目录
- ```
os.Remove(name string) error- 只删除一层
- 相当于
linux
命令rm
```
os.RemoveAll(path string) error1
2
3
4
5
6
7
8
9
10
11
12
13
14
- 删除path指定的文件,或目录及它包含的任何下级对象
- 相当于`linux`命令`rm -r`
## 文件的读写操作
## 读取文件
- `os.Open(filename)` --> `*File`
- ```go
file.Read([]byte) --> n, err- 单次读取的字节数最大为
[]byte
的长度 n
为实际读取到的字节数- 读取到末尾时
err
为EOF(end of file)
- 单次读取的字节数最大为
file.Close()
关闭文件
1 | //step1:打开文件 |
写入文件与读取类似
os.Open(filename) --> *File
file.Write([]byte) --> n, err
- 将
[]byte
中的数据写入文件
- 将
file.WriteString(string) --> n, err
- 将string写入文件
file.Close()
文件复制
- ```
io.Copy(dst Writer, src Reader) (written int64, err error)func copyFile(srcFile, destFile string) (int64, error) {1
2
3
- dst和src为实现了接口io.Writer和io.Reader的实例
file1, err := os.Open(srcFile)
if err != nil {
}return 0, err
file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
if err != nil {
}return 0, err
defer file1.Close()
defer file2.Close()
return io.Copy(file2, file1)
}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
## ioutil包
* `ReadFile() --> ([]byte, error)`
* 读取所有数据,返回字节数组
* `WriteFile(filename string, data []byte, perm os.FileMode) --> error`
* 文件不存在则创建文件,存在则清空文件
* `os.FileMode`可以直接用0666或者0777
* `ReadDir() --> ([]os.FileInfo, error)`
* 读取一个目录下的字内容,目录或文件,但是只有一层
* 返回一个`os.FileInfo`切片
```go
data, err := ioutil.ReadFile("aa.txt")
fmt.Println(string(data))
if err != nil {
fmt.Println(err)
return
}
err = ioutil.WriteFile("bb.txt", data, 0666)
if err != nil {
fmt.Println(err)
return
}
fileInfos, err := ioutil.ReadDir(".")
if err != nil {
fmt.Println(err)
return
}
for i := range fileInfos {
fmt.Println(i, fileInfos[i].IsDir(), fileInfos[i].Name())
bufio包
bufio
包实现了有缓冲的I/O
bufio
封装了一个Reader
݊及Writer
结构体,分别实现了io.Reader
和io.Writer
接口- 通过对对
io
模块的封装,提供了带有缓冲的io
操作,减小了大块数据读写的io开销
io.Reader和io.Writer
1 | type Reader interface { |
os.Open(name string) (*File, error)
返回的文件指针就实现了io.Reader
bufio.Reader结构体
NewReader(rd io.Reader) *Reader
NewReader
创建一个具有默认大小缓冲、从r读取的*Reader
Reader.Read(p []byte) (n int, err error)
Read
读取数据写入p。本方法返回写入p的字节数- 返回值n可能小于
len(p)
,读取到达结尾时,返回值n将为0而err将为io.EOF
- 类似
File.Read()
方法
1 | s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") |
- ```go
Reader.ReadBytes(delim byte) (line []byte, err error)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- `delim`是`delimiter`的缩写意为定位符
- `ReadBytes`读取直到第一次遇到`delim`字节,返回一个包含已读取的数据和`delim`字节的切片
```go
s := strings.NewReader("ABCDEFG\n123456\n")
br := bufio.NewReader(s)
for {
sli, err := br.ReadBytes('\n')
if err err == io.EOF {
break
}
fmt.Println(sli)
}
// [65 66 67 68 69 70 71 10]
// [49 50 51 52 53 54 10]
- ```go
Reader.ReadString(delim byte) (line string, err error)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 返回的是字符串类型
```go
s := strings.NewReader("ABCDEFG\n123456\n")
br := bufio.NewReader(s)
for {
s, err := br.ReadString('\n')
if err err == io.EOF {
break
}
fmt.Print(s)
}
// ABCDEFG
// 123456
bufio.Writer结构体
NewWriter(w io.Writer) *Writer
NewWriter
创建一个具有默认大小缓冲、写入w的*Writer
Writer.Write(p []byte) (nn int, err error)
Write
将p的内容写入缓冲。返回写入的字节数。如果返回值nn < len(p)
,还会返回一个错误说明原因- 类似
File.Write()
方法
Writer.WriteString(s string) (int, error)
- 写入一个字符串,返回写入的字节数
Writer.Flush() error
- Flush方法将缓冲中的数据输出
1 | file1, _ := os.Open("aa.txt") |
bufio.Scanner结构体
NewScanner(r io.Reader) *Scanner
- 创建并返回一个从r读取数据的Scanner,默认的分割函数是ScanLines
- 通过
Scanner.Split(split SplitFunc)
方法,可以为Scanner指定splitFunc - Scanner可以通过plitFunc将r中的数据拆分为多个token,然后通过Scanner.Scan()依次读取
bufio中提供的默认
splitFunc
:ScanBytes
,按照byte进程拆分ScanRunes
,按照行(“\n”)进程拆分ScanWords
,按照utf-8字符进行拆分ScanLines
,按照单词(“ “)进程拆分
常用方法
Split(split SplitFunc)
Scan() bool
Text() string
Bytes() []byte
1 | scanner := bufio.NewScanner(os.Stdin) |
参考:
https://www.jianshu.com/p/abc396787a32
https://blog.csdn.net/sinat_39786086/article/details/87726361