Golang 中的文件操作
优质
小牛编辑
142浏览
2023-12-01
文件的打开和关闭
和 C 语言一样,Go语言中操作文件也是通过一个 FILE 结构体
type file struct { pfd poll.FD name string dirinfo *dirInfo } type File struct { *file // os specific }
Open 函数
- func Open(name string) (file *File, err error)
- Open 打开一个文件用于
读取
Close 函数
- func (f *File) Close() error
- Close 关闭文件 f
package main import ( "fmt" "os" ) func main() { // 1.打开一个文件 // 注意: 文件不存在不会创建, 会报错 // 注意: 通过Open打开只能读取, 不能写入 fp, err := os.Open("d:/lnj.txt") if err != nil{ fmt.Println(err) }else{ fmt.Println(fp) } // 2.关闭一个文件 defer func() { err = fp.Close() if err != nil { fmt.Println(err) } }() }
文件读取
Read 函数(不带缓冲区去读)
- func (f *File) Read(b []byte) (n int, err error)
- Read 方法从f中读取最多 len(b) 字节数据并写入 b
package main import ( "fmt" "io" "os" ) func main() { // 1.打开一个文件 // 注意: 文件不存在不会创建, 会报错 // 注意: 通过Open打开只能读取, 不能写入 fp, err := os.Open("d:/lnj.txt") if err != nil{ fmt.Println(err) }else{ fmt.Println(fp) } // 2.关闭一个文件 defer func() { err = fp.Close() if err != nil { fmt.Println(err) } }() // 3.读取指定指定字节个数据 // 注意点: \n也会被读取进来 //buf := make([]byte, 50) //count, err := fp.Read(buf) //if err != nil { // fmt.Println(err) //}else{ // fmt.Println(count) // fmt.Println(string(buf)) //} // 4.读取文件中所有内容, 直到文件末尾为止 buf := make([]byte, 10) for{ count, err := fp.Read(buf) // 注意: 这行代码要放到判断EOF之前, 否则会出现少读一行情况 fmt.Print(string(buf[:count])) if err == io.EOF { break } } }
ReadBytes 和 ReadString 函数(带缓冲区去读)
- func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
- ReadBytes 读取直到第一次遇到 delim 字节
- func (b *Reader) ReadString(delim byte) (line string, err error)
- ReadString 读取直到第一次遇到 delim 字节
package main import ( "bufio" "fmt" "io" "os" ) func main() { // 1.打开一个文件 // 注意: 文件不存在不会创建, 会报错 // 注意: 通过Open打开只能读取, 不能写入 fp, err := os.Open("d:/lnj.txt") if err != nil{ fmt.Println(err) }else{ fmt.Println(fp) } // 2.关闭一个文件 defer func() { err = fp.Close() if err != nil { fmt.Println(err) } }() // 3.读取一行数据 // 创建读取缓冲区, 默认大小4096 //r :=bufio.NewReader(fp) //buf, err := r.ReadBytes('\n') //buf, err := r.ReadString('\n') //if err != nil{ // fmt.Println(err) //}else{ // fmt.Println(string(buf)) //} // 4.读取文件中所有内容, 直到文件末尾为止 r :=bufio.NewReader(fp) for{ //buf, err := r.ReadBytes('\n') buf, err := r.ReadString('\n') fmt.Print(string(buf)) if err == io.EOF{ break } } }
ReadFile 函数
- func ReadFile(filename string) ([]byte, error)
- 从 filename 指定的文件中读取数据并返回文件的所有内容
- 不适合大文件读取
package main import ( "fmt" "io/ioutil" ) func main() { filePath := "d:/lnj.txt" buf, err := ioutil.ReadFile(filePath) if err !=nil { fmt.Println(err) }else{ fmt.Println(string(buf)) } }
文件创建和写入
Create 函数
- func Create(name string) (file *File, err error)
- Create 采用模式 0666(任何人都可读写,不可执行)创建一个名为 name 的文件
- 如果文件存在会覆盖原有文件
Write 函数
- func (f *File) Write(b []byte) (n int, err error)
- 将指定字节数组写入到文件中
WriteString 函数
- func (f *File) WriteString(s string) (ret int, err error)
- 将指定字符串写入到文件中
package main import ( "fmt" "os" ) func main() { // 1.创建一个文件 fp, err := os.Create("d:/lnj.txt") if err != nil{ fmt.Println(err) } // 2.关闭打开的文件 defer func() { err := fp.Close() if err != nil { fmt.Println(err) } }() // 2.往文件中写入数据 // 注意: Windows换行是\r\n bytes := []byte{'l','n','j','\r','\n'} fp.Write(bytes) fp.WriteString("www.it666.com\r\n") fp.WriteString("www.itzb.com\r\n") // 注意: Go语言采用UTF-8编码, 一个中文占用3个字节 fp.WriteString("李南江") }
OpenFile 函数
- func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
- 第一个参数:打开的路径
- 第二个参数:打开的模式
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 // 如果可能,打开时清空文件 )
第三个参数:指定权限
- 0.没有任何权限
- 1.执行权限(如果是可执行程序,可以运行)
- 2.写权限
- 3.写权限和执行权限
- 4.读权限
- 5.读权限和执行权限
- 6.读权限和写权限
- 7.读权限和写权限以及执行权限
const ( // 单字符是被String方法用于格式化的属性缩写。 ModeDir FileMode = 1 << (32 - 1 - iota) // d: 目录 ModeAppend // a: 只能写入,且只能写入到末尾 ModeExclusive // l: 用于执行 ModeTemporary // T: 临时文件(非备份文件) ModeSymlink // L: 符号链接(不是快捷方式文件) ModeDevice // D: 设备 ModeNamedPipe // p: 命名管道(FIFO) ModeSocket // S: Unix域socket ModeSetuid // u: 表示文件具有其创建者用户id权限 ModeSetgid // g: 表示文件具有其创建者组id的权限 ModeCharDevice // c: 字符设备,需已设置ModeDevice ModeSticky // t: 只有root/创建者能删除/移动文件 // 覆盖所有类型位(用于通过&获取类型位),对普通文件,所有这些位都不应被设置 ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice ModePerm FileMode = 0777 // 覆盖所有Unix权限位(用于通过&获取类型位) )
不带缓冲区写入
package main import ( "fmt" "os" ) func main() { // 注意点: 第三个参数在Windows没有效果 // -rw-rw-rw- (666) 所有用户都有文件读、写权限。 //-rwxrwxrwx (777) 所有用户都有读、写、执行权限。 // 1.打开文件 //fp, err := os.OpenFile("d:/lnj.txt", os.O_CREATE|os.O_RDWR, 0666) fp, err := os.OpenFile("d:/lnj.txt", os.O_CREATE|os.O_APPEND, 0666) if err != nil { fmt.Println(err) } // 2.关闭打开的文件 defer func() { err := fp.Close() if err != nil { fmt.Println(err) } }() // 注意点: // 如果O_RDWR模式打开, 被打开文件已经有内容, 会从最前面开始覆盖 // 如果O_APPEND模式打开, 被打开文件已经有内容, 会从在最后追加 // 3.往文件中写入数据 bytes := []byte{'l','n','j','\r','\n'} fp.Write(bytes) fp.WriteString("www.it666.com\r\n") }
带缓冲区写入
package main import ( "bufio" "fmt" "os" ) func main() { // 1.打开文件 fp, err := os.OpenFile("d:/lnj.txt", os.O_CREATE|os.O_APPEND, 0666) if err != nil { fmt.Println(err) } // 2.关闭打开的文件 defer func() { err := fp.Close() if err != nil { fmt.Println(err) } }() // 3.创建缓冲区 w := bufio.NewWriter(fp) // 4.写入数据到缓冲区 bytes := []byte{'l','n','j','\r','\n'} w.Write(bytes) w.WriteString("www.it666.com\r\n") // 5.将缓冲区中的数据刷新到文件 w.Flush() }
WriteFile 函数
package main import ( "fmt" "io/ioutil" ) func main() { // 1.写入数据到指定文件 data := []byte{'l','n','j','\r','\n'} err := ioutil.WriteFile("d:/abc.txt", data, 0666) if err != nil { fmt.Println(err) }else{ fmt.Println("写入成功") } }
判断文件是否存在
Stat 函数
- func Stat(name string) (fi FileInfo, err error)
- 返回值:FileInfo
type FileInfo interface { Name() string // 文件的名字(不含扩展名) Size() int64 // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同 Mode() FileMode // 文件的模式位 ModTime() time.Time // 文件的修改时间 IsDir() bool // 等价于Mode().IsDir() Sys() interface{} // 底层数据来源(可以返回nil) }
返回值: error
- 返回值 error 等于 nil,代表文件存在
- 返回值 error 不等于 nil,可以进一步通过 IsNotExist 判断,如果返回 true 代表文件不存在
- 返回值 error 如果返回其它错误,则不确定文件是否存在
package main import ( "fmt" "os" ) func main() { info, err := os.Stat("d:/lnj.txt") if err == nil { fmt.Println("文件存在") fmt.Println(info.Name()) }else if os.IsNotExist(err) { fmt.Println("文件不存在") }else{ fmt.Println("不确定") } }
练习
将一个文本文件拷贝到另外一个文件中,尝试用上面学习的其它方法实现下
package main import ( "fmt" "io/ioutil" ) func main() { // 1.读取一个文件 buf, err := ioutil.ReadFile("d:/lnj.txt") if err != nil { fmt.Println(err) return } // 2.写入读取的数据到另一个文件 err =ioutil.WriteFile("d:/abc.txt", buf, 0666) if err != nil { fmt.Println(err) return } fmt.Println("拷贝完成") }
将一个图片/视频文件拷贝到另一个文件
package main import ( "bufio" "fmt" "io" "os" ) func main() { // 1.定义拷贝文件的路径 scrPath := "D:/a.png" destPath := "E:/b.png" // 2.打开被拷贝文件 fr, err := os.Open(scrPath) if err != nil { fmt.Println(err) return } // 3.关闭打开文件 defer func() { err := fr.Close() if err != nil{ fmt.Println(err) } }() // 4.创建读取缓冲区 r := bufio.NewReader(fr) // 1.创建写入文件 fw, err := os.Create(destPath) if err != nil { fmt.Println(err) return } // 2.关闭打开文件 defer func() { err := fw.Close() if err != nil{ fmt.Println(err) } }() // 3.创建写入缓冲区 w := bufio.NewWriter(fw) // 4.利用系统copy函数完成拷贝 count, err := io.Copy(w, r) if err != nil { fmt.Println(err) return } fmt.Println(count) fmt.Println("拷贝完成") }
自己查文档实现遍历文件夹
- 例如:给一个文件夹路径, 获取该文件夹下所有文件,并将所有文件路径保存到切片中