type
Post
status
Published
date
Aug 21, 2021
slug
summary
tags
Golang
category
技术分享
icon
password
打开文件os.Createos.Openos.OpenFile()文件读取file.Read()bufio 包ioutil包文件写入Write()bufio.NewWriterioutil.WriteFile文件拷贝缓冲区中转io.Copy()目录操作打开目录读目录
打开文件
os.Create
创建指定目录和名词的文件,如果已经存在则清空原有文件
- 参数:文件名 name
- 打开文件的路径: 绝对路径或相对路径
- 目录分割符:/
os.Open
os.Open()以只读方式打开一个文件,返回一个文件句柄 File 和 err
- 对文件句柄调用
close()方法能够关闭文件 - 为了防止文件忘记关闭,使用 defer注册文件关闭语句
func main(){ file,err := os.Open(".//main.go") if err!= nil{ fmt.Println("open file failed,err:",err) return } file.Close() }
os.OpenFile()
能以指定模式打开文件,如果要写入文件必须使用此方法
func OpenFile(name string, flag int, perm FileMode) (*File, error)
- flag: 模式标识符,多个模式用 | 分隔 (位运算或,二进制位有一个是1就为1)

- perm :文件权限,r(读)4,w(写)2,x(执行)1 数字相加,就是LInux 的文件权限表示方法,如果运行读写和执行,则传 0666
file, err := os.OpenFile("xx.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if err != nil { fmt.Println("open file failed, err:", err) return } defer file.Close()
文件读取
file.Read()
func (f *File) Read(b []byte) (n int, err error)
- 接收一个字节切片,存放读到的数据。切片的长度就是一次读的文件长度。
- 返回本次读取的字节数和可能出现的错误
- 读到文件末尾时会返回 0 和 io.EOF
基本使用
func main() { // 只读方式打开当前目录下的main.go文件 file, err := os.Open("./main.go") if err != nil { fmt.Println("open file failed!, 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("read file failed, err:", err) return } fmt.Printf("读取了%d字节数据\n", n) fmt.Println(string(tmp[:n])) //读了多少就切到多少 }
使用 for 循环读取文件中的所有数据
func main() { // 只读方式打开当前目录下的main.go文件 file, err := os.Open("./main.go") if err != nil { fmt.Println("open file failed!, err:", err) return } defer file.Close() // 循环读取文件 var content []byte var tmp = make([]byte, 128) for { n, err := file.Read(tmp) if err == io.EOF { fmt.Println("文件读完了") break } if err != nil { fmt.Println("read file failed, err:", err) return } content = append(content, tmp[:n]...) } fmt.Println(string(content)) }
bufio 包
bufio 包是对 file 的封装,支持更多的功能(比如按行读)且有缓冲区,性能更好
- 创建带有缓冲区的读写器:
bufio.NewReader(file)
- 从reader 缓冲区中读取指定长度数据:
reader.ReadString
- 判断到达文件结尾:
err≠nil && err == io.EOF
文件结束标记EOF需要单独读一次才能获取到的
// bufio按行读取示例 func main() { file, err := os.Open("./xx.txt") if err != nil { fmt.Println("open file failed, err:", err) return } defer file.Close() //创建带有缓冲区的用来从文件读内容的对象 reader := bufio.NewReader(file) for { //按行读,指定换行符。返回读到的字符串和错误信息 line, err := reader.ReadString('\n') //注意是字符 if err == io.EOF { if len(line) != 0 { fmt.Println(line) } fmt.Println("文件读完了") break } if err != nil { fmt.Println("read file failed, err:", err) return } fmt.Print(line) } }
ioutil包
常用来读取整个文件
func main() { content, err := ioutil.ReadFile("./main.go") if err != nil { fmt.Println("read file failed, err:", err) return } fmt.Println(string(content)) }
文件写入
Write()
Write写入准备好的数据
WriteString直接写入字符串(只能从起始位置写,会覆盖),返回写入的字节个数
func main() { file, err := os.OpenFile("xx.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if err != nil { fmt.Println("open file failed, err:", err) return } defer file.Close() str := "hello" file.Write([]byte(str)) //写入字节切片数据 file.WriteString("hello world") //直接写入字符串数据 }
Seek(偏移量,偏移起始位置)修改(获取)文件读写指针- 偏移量:正数向文件尾偏,负数往头偏
- 起始位置:
io.SeekStart起始位置io.SeekCurrent当前位置io.SeekEnd结尾位置- 返回值:从起始位置到当前读写指针的偏移量
WriteAt(b []byte,off int64)通常搭配 seek- 写入的数据
- 偏移量
bufio.NewWriter
writeXXX将数据先写入到缓存
- 需要
. Flush()将缓冲区内容刷新。
func main() { file, err := os.OpenFile("xx.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if err != nil { fmt.Println("open file failed, err:", err) return } defer file.Close() //使用bufio.NewWriter创建写的对象 writer := bufio.NewWriter(file) for i := 0; i < 10; i++ { writer.WriteString("hello沙河\n") //将数据先写入缓存 } //必须将缓存中的内容写入文件 writer.Flush() }
ioutil.WriteFile
func main() { str := "hello" err := ioutil.WriteFile("./xx.txt", []byte(str), 0666) if err != nil { fmt.Println("write file failed, err:", err) return } }
文件拷贝
缓冲区中转
// 打开读的文件 f_r, err := os.Open("C:/itcast/01-复习.avi") if err != nil { fmt.Println("Open err: ", err) return } defer f_r.Close() // 创建写的文件 f_w, err := os.Create("C:/itcast/test.avi") if err != nil { fmt.Println("Create err: ", err) return } defer f_w.Close() // 从读文件中获取数据,放到缓冲区中。 buf := make([]byte, 4096) // 循环从读文件中,获取数据,“原封不动的”写到写文件中。 for { n, err := f_r.Read(buf) if err != nil && err == io.EOF { fmt.Printf("读完。n = %d\n", n) return } f_w.Write(buf[:n]) // 读多少,写多少 }
io.Copy()
// CopyFile 拷贝文件函数 func CopyFile(dstName, srcName 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() { _, err := CopyFile("dst.txt", "src.txt") if err != nil { fmt.Println("copy file failed, err:", err) return } fmt.Println("copy done!") }
目录操作
目录中的文件和文件夹都称为目录项,文件夹也是文件的一种
打开目录
同样使用
OpenFile 函数,但第三个参数通常传 os.ModeDir ,返回一个可以读写目录的文件指针func OpenFile(name string, flag int, perm FileMode) (*File, error) { ... }
读目录
func (f *File) ReadDir(n int) ([]FileInfo,error)
- 参数:指定读几个目录项,如果要读所有目录,通常传 -1
- 返回值:返回文件(文件和目录)结构信息
type FileInfo interface{ Name() string //文件名 Size() int64 //文件大小 Mode() int64 //访问权限 ModTime() time.Time //最后修改时间 IsDir() bool //是否是目录 Sys() interface{} // ... }
得到 FileInfo 类型切片后,就可以 range 遍历切片,使用接口方法获文件信息
其他API
Chdir(dir string)修改当前工作目录
Getwd()返回当前工作目录绝对路径
Mkdir(name string,perm FileMode)以指定权限创建目录