os.Open(name string)
方法以只读方式打开文件,os 包还提供了 os.OpenFile(name string, flag int, perm FileMode)
方法,通过指定额外的 读写方式
和 文件权限
参数,使文件操作变得更为灵活。
其中,flag 有以下几种常用的值:
对于文件权限参数,Linux系统中采用四位八进制数组成权限,比如0644 。对于每个新创建的文件或目录,系统都会自动赋予一个默认的权限。
可以使用umask
命令设置文件或目录的默认权限。系统默认的权限掩码是0022
。
通常新建文件的默认权限值为0666,新建目录的默认权限为0777,需要与当前的权限掩码0022相减,可以得到0644
和0755
。
读文件
func main() {
// 打开文件返回一个句柄
file, _ := os.Open("D:\\Desktop\\readme.txt")
defer file.Close()
// 缓冲区
buf := make([]byte, 1024)
// 存放文件所有内容
var bytes []byte
for {
// 每次读取一行放入缓冲区
count, err := file.Read(buf)
if err == io.EOF {
break
}
bytes = append(bytes, buf[:count]...)
}
fmt.Println(string(bytes))
}
写文件
可以通过 Write()
和 WriteString()
方法写入数据,最后通过 Sync()
方法将数据持久化到磁盘:
func main() {
file, _ := os.OpenFile("D:\\Desktop\\readme.txt", os.O_RDWR | os.O_APPEND | os.O_CREATE, 0644)
defer file.Close()
data := []byte("hello\nyes\nno\n")
// 写入字节
count, _ := file.Write(data)
fmt.Println("第一次写入", count, "字节")
// 写入字符串
count, _ = file.WriteString("write string\n")
fmt.Println("第二次写入", count, "字节")
// 确保写入磁盘
file.Sync()
}
读文件
一次性读入所有内容:
func main() {
bytes, _ := ioutil.ReadFile("D:\\Desktop\\readme.txt")
fmt.Println(string(bytes))
}
逐行读入:
func main() {
file, _ := os.Open("D:\\Desktop\\readme.txt")
defer file.Close()
// 接受io.Reader类型参数 返回一个bufio.Scanner实例
scanner := bufio.NewScanner(file)
var count int
for scanner.Scan() {
count++
// 读取当前行内容
line := scanner.Text()
fmt.Println(count, ": " ,line)
}
}
写文件
覆盖写入:
func main() {
data := []byte("hello\nyes\nno\n")
ioutil.WriteFile("D:\\Desktop\\readme.txt", data, 0664)
}
追加:
func main() {
// 以指定的权限打开文件
file, _ := os.OpenFile("D:\\Desktop\\readme.txt", os.O_RDWR | os.O_APPEND | os.O_CREATE, 0664)
defer file.Close()
data := []byte("greet\n")
// 写入字节
count, _ := file.Write(data)
fmt.Println("第一次写入", count, "字节")
// 写入字符串
count, _ = file.WriteString("echo\n")
fmt.Println("第二次写入", count, "字节")
// 确保落盘
file.Sync()
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
其实io 包就是围绕着实现了 io.Writer 和 io.Reader 接口类型的值而构建的。比如os.File
、io.Copy
、io.WriteString
、io.PipeWriter/Reader
、ioutil
等等都实现了这两个接口,所以它们都可以读文件和写文件。当然我们也可以自行实现这两个接口。
在学习godis时,在aof.go文件中我看到一个关于io流的函数:io.LimitReader
。该函数用于返回指定大小的Reader。
// LimitReader returns a Reader that reads from r
// but stops with EOF after n bytes.
// The underlying implementation is a *LimitedReader.
func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
下面演示一下基本的使用:
func main() {
file, _ := os.Open("D:\\Desktop\\readme.txt")
res := io.LimitReader(file, 20)
data := make([]byte, 1024)
count, err := res.Read(data)
if err != nil {
return
}
fmt.Println(string(data[:count]))
}
其中,res是一个Reader,且res只获取到了从文件开始往后20字节的内容。