Go语言文件操作
更多用法,参考GO语言标准库
获取文件信息
os.Stat()函数,返回fileInfo和err信息。
func main() {
fileInfo, err := os.Stat("xx/test.txt")
if err != nil {
fmt.Println("get info err", err)
return //将函数返回
}
//获取文件名
fmt.Println(fileInfo.Name()) //test.txt
//获取文件大小
fmt.Println(fileInfo.Size()) //540
//是否为目录
fmt.Println(fileInfo.IsDir()) //false
//修改时间
fmt.Println(fileInfo.ModTime()) //2019-08-28 11:28:33.405318773 +0800 CST
//权限
fmt.Println(fileInfo.Mode()) //-rw-r--r--
}
创建目录与文件操作
os.Mkdir()函数与os.Mkdirall()函数能够创建目录。os.Mkdirall()相当于mkdir -p。
//创建目录 err = os.Mkdir("/Users/wangxin/go/src/github.com/file/fileinfo1/test1", os.ModePerm) if err != nil { fmt.Println("err:", err) return } fmt.Println("文件创建成功") err = os.MkdirAll("/Users/wangxin/go/src/github.com/file/fileinfo1/test/test1/test2", os.ModePerm) if err != nil { fmt.Println("err:", err) return } fmt.Println("文件创建成功") //创建文件,文件不存在会创建,存在会重置,创建相对路径文件,是以工程目录为参照 file1, err := os.Create("/Users/wangxin/go/src/github.com/file/fileinfo1/test1/test.txt") if err != nil { fmt.Println("err:", err) return } fmt.Println(file1)
打开和关闭文件
os.Open()函数能够打开一个文件,返回一个*File和一个err,通过此种方式打开文件是只读的。
file.close()方法能够关闭文件。
//打开和关闭文件
func main() {
file,err := os.Open("test.txt")
if err != nil{
fmt.Println("打开文件失败",err)
return
}
//文件能打开的情况下,使用defer延迟关闭文件
defer file.Close()
}
读取文件
基本使用
file.Read()方法可以读取文件,它接收一个字节切片,返回读取的字节数和可能的具体错误,读到文件末尾时会返回0和io.EOF。
定义:
func (f *File) Read(b []byte) (n int, err error)
type Reader interface {
Read(p []byte) (n int, err error)
}
示例:
func main() {
//打开文件
f,err := os.Open("woceng.txt")
if err!= nil{
fmt.Println("文件打开失败",err)
return
}
//关闭文件
defer f.Close()
//读取文件
var geci = make([]byte,256)
g,err := f.Read(geci)
if err == io.EOF{
fmt.Println("文件读取完毕!")
return
}
if err!= nil{
fmt.Println("文件打开失败",err)
return
}
//只会读取之前切片定义的256字节数据,若文件内容大于256字节,则超出部分无法显示
fmt.Printf("读取了%d字节数据\n", g)
fmt.Println(string(geci[:g])) //将byte转换成string
}
循环读取
使用for循环读取。
var geci = make([]byte,256)
for {
g,err := f.Read(geci)
if err == io.EOF{
fmt.Println("文件读取完毕!")
return
}
if err!= nil{
fmt.Println("文件打开失败",err)
return
}
//会全部读取,但是每256字节会进行重新读取,可能会出现乱码
fmt.Printf("读取了%d字节数据\n", g)
fmt.Println(string(geci[:g]))
}
bufio读取文件
读取文件中会有个缓冲区,先把内容读到缓冲区,然后统一读取,不过可能会丢数据(内存)。
func main() {
file,err := os.Open("woceng.txt")
if err != nil{
fmt.Println("文件读取错误",err)
return
}
defer file.Close()
// 利用缓冲区从文件读数据
reader := bufio.NewReader(file)
for{
line,err := reader.ReadString(\'\n\') //字符串读取,每到换行就停止
if err == io.EOF {
fmt.Println("文件读完了")
break
}
if err != nil {
fmt.Println("read file failed, err:", err)
return
}
fmt.Print(line)
}
}
ioutil读取整个文件
ReadFile方法能够读取完整的文件,只需要将文件名作为参数传入。
// ioutil读取文件
func readioutil(filename string) {
content,err := ioutil.ReadFile(filename)
if err != nil{
fmt.Println("文件读取错误",err)
return
}
fmt.Println(string(content))
}
文件写入
os.OpenFile()方法实现文件写入相关功能。
语法:
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
...
}
type Writer interface {
Write(p []byte) (n int, err error)
}
name:要打开的文件名
flag:打开文件的模式
perm:文件权限,一个八进制数
模式 | 含义 |
---|---|
os.O_WRONLY | 只写 |
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
Write和WriteString
//打开文件支持文件写入
func main() {
file,err := os.OpenFile("test.txt",os.O_CREATE|os.O_APPEND|os.O_WRONLY,0644)
if err != nil{
fmt.Println("打开文件失败",err)
return
}
defer file.Close()
str := "ares"
file.Write([]byte("666\n")) //写入字节切片数据
file.WriteString(str) //直接写入字符串数据
}
bufio.NewWriter
将数据先写入缓存。
//打开文件支持文件写入
func main() {
file,err := os.OpenFile("test.txt",os.O_CREATE|os.O_APPEND|os.O_WRONLY,0644)
if err != nil{
fmt.Println("打开文件失败",err)
return
}
defer file.Close()
writer := bufio.NewWriter(file)
for i := 0;i<10;i++{
writer.WriteString("heoolo\n") ////将数据先写入缓存
}
writer.Flush() //将缓存中的内容写入文件
}
ioutil.WriteFile
将内容直接写入文件中,避免了打开文件操作。直接覆盖文件内容
func main() {
str := "aresares"
err := ioutil.WriteFile("test.txt",[]byte(str),0644)
if err != nil{
fmt.Println("写文件失败",err)
return
}
}
ioutil.ReadDir实现文件目录遍历
func listFiles(dirname string, level int) {
// level用来记录当前递归的层次
s := "--" //生成空格
for i := 0; i < level; i++ {
s = "| " + s
}
fileInfos, err := ioutil.ReadDir(dirname)
if err != nil {
fmt.Println("err:", err)
}
for _, fi := range fileInfos {
filename := dirname + "/" + fi.Name()
fmt.Printf("%s%s\n", s, filename)
if fi.IsDir() {
listFiles(filename, level+1)
}
}
}
func main() {
//目录遍历
dirname := "/Users/wangxin/Documents"
listFiles(dirname, 0)
}
文件复制
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
)
func main() {
srcFile := "xx/src.txt"
destFile := "xx/dest1.txt"
total, err := CopyFile(srcFile, destFile)
fmt.Println(total, err)
total1, err := CopyFile1(srcFile, destFile)
fmt.Println(total1, err)
total2, err := CopyFile3(srcFile, destFile)
fmt.Println(total2, err)
}
//使用io.Copy()方法实现拷贝,返回拷贝的总数量,错误
func CopyFile(srcFile, destFile string) (int64, error) {
file1, err := os.Open(srcFile)
if err != nil {
return 0, err
}
file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
if err != nil {
return 0, err
}
defer file1.Close()
defer file2.Close()
return io.Copy(file2, file1)
}
//通过io操作实现文件拷贝,返回拷贝的总数量及错误
func CopyFile1(srcFile, destFile string) (int, error) {
file1, err := os.Open(srcFile)
if err != nil {
return 0, err
}
file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
if err != nil {
return 0, err
}
defer file1.Close()
defer file2.Close()
//读写
str := make([]byte, 100, 100) //拷贝的时间与此处定义的大小有关
n := -1 //读取的数据量
total := 0
for {
n, err = file1.Read(str)
if err == io.EOF || n == 0 {
fmt.Println("拷贝结束!")
break
} else if err != nil {
fmt.Println("copy err", err)
return total, err
}
total += n
file2.Write([]byte("\n"))
file2.Write(str[:n])
}
return total, nil
}
//通过ioutil操作实现文件拷贝,返回拷贝的总数量及错误,不适用大文件
func CopyFile3(srcFile, destFile string) (int, error) {
str, err := ioutil.ReadFile(srcFile)
if err != nil {
return 0, err
}
err = ioutil.WriteFile(destFile, str, 0644)
if err != nil {
return 0, err
}
return len(str), nil
}
断点续传
Seeker接口
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
offset:设置偏移量
whence:
- 0:seekStart表示相对于文件开始,
- 1:seekCurrent表示相对于当前偏移量,
- 2:seek end表示相对于结束。
func main() {
file, _ := os.OpenFile("xx/file01/src.txt", os.O_RDWR, 0644)
defer file.Close()
//创建一个切片
str := []byte{0}
file.Read(str)
fmt.Println(string(str)) //A
file.Seek(2, io.SeekStart) //相对文件开始从下标为2的位置开始读取文件
file.Read(str)
fmt.Println(string(str)) //C
file.Seek(3, io.SeekCurrent) //相对于当前位置(下标为2)往后3个偏移量位置读取文件
file.Read(str)
fmt.Println(string(str)) //G
file.Seek(2, io.SeekEnd) //相对于文件末尾,写入文件
file.WriteString("QWE") //会在文件末尾写入QWE
}
断点续传实现
创建一个临时文件,记录已经传递的数据量,当恢复传递的时候,先从临时文件中读取上次已经传递的数据量,然后通过Seek()方法,设置到该读和该写的位置,再继续传递数据。
//定义一个错误处理函数
func HandleErr(err error) {
if err != nil {
fmt.Println(err)
}
}
func main() {
srcFile := "xx/src.txt"
destFile := "xx/src1.txt"
//destFile := srcFile[strings.LastIndex(srcFile, "/")+1:] + "dest.txt" //获取源文件名
tempFile := destFile + "tmp.txt" //临时文件
//fmt.Println(srcFile)
//fmt.Println(destFile)
//fmt.Println(tempFile)
file1, err := os.Open(srcFile)
HandleErr(err)
file2, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0644)
HandleErr(err)
file3, err := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, 0644)
HandleErr(err)
defer file1.Close()
defer file2.Close()
//读取临时文件中的数据
file3.Seek(0, io.SeekStart)
//创建切片存储临时文件数据
bs := make([]byte, 100, 100)
n1, err := file3.Read(bs)
HandleErr(err)
fmt.Println(n1)
countStr := string(bs[:n1]) //获取临时文件的数据
couunt, _ := strconv.ParseInt(countStr, 10, 64) //将数据转为10进制64位数据
fmt.Println(couunt)
//设置读写的偏移量
file1.Seek(couunt, io.SeekStart)
file2.Seek(couunt, io.SeekStart)
data := make([]byte, 1024, 1024)
n2 := -1 //读的数据量
n3 := -1 //写的数据量
total := int(couunt) //读取总量
//读取数据
for {
n2, err = file1.Read(data)
if err == io.EOF || n2 == 0 {
fmt.Println("复制完毕、、")
file3.Close()
//删除临时文件
os.Remove(tempFile)
break
}
//将数据写入目标文件
n3, _ = file2.Write(data[:n2])
total += n3
//将复制总量,存储到临时文件中
file3.Seek(0, io.SeekStart)
file3.WriteString(strconv.Itoa(total))
}
}