IO
I input 输入 、写
O output 输出 、 读
os常用包
操作文件和文件夹相关的
func main() {
fixx, err := os.Stat("./pojo/User.go")
if err != nil {
return
}
fmt.Println(fixx.Name()) //取文件的名字
fmt.Println(fixx.Mode()) //文件的权限
// linux中2种权限定义方式,一种字母,一种8进制,-代表文件,d代表目录, r代表可读04,w代表可写02,x代表可执行01 也可以用0777代替
fmt.Println(fixx.ModTime()) //最后的修改时间
fmt.Println(fixx.IsDir()) //是不是文件夹
fmt.Println(fixx.Size()) //文件的大小(字节)
//反射获取文件更详细的信息
fmt.Println(fixx.Sys()) //&{16 {2247817508 30994319} {4286871947 30994434} {1396014605 30994321} 0 0}
}
创建文件夹和多级文件夹
func main() {
//创建单级目录,已有的话会报错。
err := os.Mkdir("./pojo2", os.ModePerm) //后面是权限,也可以用0777代替
if err != nil {
fmt.Println(err)
}
//创建多级目录,已有的话不会报错,没有的话会创建
err = os.MkdirAll("./pojo2/a/b/c", os.ModePerm) //后面是权限,也可以用0777代替
if err != nil {
fmt.Println(err)
}
}
删除
func main() {
//删除单目录,里面没文件的,其他情况会报错
err := os.Remove("./pojo2/a/b/c")
if err != nil {
fmt.Println(err)
}
//删除多目录,里面有文件的,谨慎使用
err1 := os.RemoveAll("./pojo2")
if err1 != nil {
fmt.Println(err1)
}
}
创建文件
func main() {
//参数是一个,地址加文件,重名文件会覆盖.
file, err0 := os.Create("./pojo/a.txt")
if err0 != nil {
fmt.Println(err0)
}
fmt.Println(file)
fmt.Println(file.Name())
//参数是2个,每次返回的后缀不一样,不知道干嘛的.
file1, err := os.CreateTemp("./pojo", "a.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(file1)
fmt.Println(file1.Name())
}
读写文件
读
1.先获取文件的指针,判断文件是否权限
2.然后os.open()建立文件流,用openfile()还可以设置打开的权限
3.创建byte类型切片
4.用os.read(切片)读出来,返回2个参数,一个长度,一个err
不知道为什么狂神打出来的aaa带了一堆缓冲区的,我的没带。
写
func main() {
//建立文件流,如果没有os.O_APPEND参数,写的时候是覆盖,有的话是追加
openinfo, err := os.OpenFile("pojo/a.txt", os.O_WRONLY|os.O_WRONLY|os.O_APPEND, os.ModePerm)
if err != nil {
fmt.Println(err)
return
}
defer openinfo.Close()
//创建byte切片
bs := make([]byte, 1024, 1024)
bs = []byte{65, 66, 67, 68, 69, 70}
//写数据到文件
i, err1 := openinfo.Write(bs)
if err1 != nil {
fmt.Println(err1)
return
}
i1, _ := openinfo.WriteString("hello,顺大大")
fmt.Println(i)
fmt.Println(i1)
}
手动复制文件
copy函数
func copy(ywj, mbwenj string, size int) {
ywjfile, err := os.Open(ywj)
if err != nil {
fmt.Println(err)
return
}
defer ywjfile.Close()
mbfile, err1 := os.OpenFile(mbwenj, os.O_WRONLY|os.O_CREATE, 777)
if err1 != nil {
fmt.Println(err1)
return
}
defer mbfile.Close()
//缓冲区
buf := make([]byte, size)
for {
//读
n, err := ywjfile.Read(buf)
if err == io.EOF || n == 0 {
fmt.Println("文件复制完毕了")
break
}
//写
_, err2 := mbfile.Write(buf[:n])
if err2 != nil {
fmt.Println("写出失败", err2)
}
}
}
系统自带的io.copy(目标文件,源文件)函数
func copy2(mubiao, yuan string) {
//源文件流
ywjfile, err := os.Open(yuan)
if err != nil {
fmt.Println(err)
return
}
defer ywjfile.Close()
//目标文件流
mbfile, err1 := os.OpenFile(mubiao, os.O_WRONLY|os.O_CREATE, 777)
if err1 != nil {
fmt.Println(err1)
return
}
defer mbfile.Close()
written, _ := io.Copy(mbfile, ywjfile)
fmt.Println("文件大小", written)
}
系统自带的读写函数
不建议用到大文件,内存可能扛不住
func copy3(mubiao, yuan string) {
//读源文件 存到缓冲区,返回缓冲区切片
bytes, _ := os.ReadFile(yuan)
//写到目标文件,3个参数,目标地址,缓冲区,权限
os.WriteFile(mubiao, bytes, 777)
}
断点续传
Seek函数
用来设置文件读写时的光标位置,3个入参。
进行写的时候,即使文件是可读可写的,也必须用os.OpenFile加一个写的权限,不然写不进去.
读可以读,写必须Openfile加权限
func main() {
filea := "./pojo/a.txt"
//fileInfoa, _ := os.Open(filea)
//文件本身就是可读写的,也必须用可读写打开,不然没法进行读写.
fileInfoa, _ := os.OpenFile(filea, os.O_RDWR, 777)
defer fileInfoa.Close()
//业务
//用来设置读写文件流时光标的位置
fileInfoa.Seek(3, io.SeekStart) //0代表开始,1代表当前,2代表结尾
//设置缓冲区
buf := []byte{0}
//读
fileInfoa.Read(buf)
fmt.Println(string(buf))
//当光标在末尾时,可以写
fileInfoa.Seek(0, io.SeekEnd)
n, err := fileInfoa.WriteString("hahah")
if err != nil {
fmt.Println(err)
}
fmt.Println(n)
}
实操断点续传
1.创建源文件,目标文件,临时文件的流
2.读临时文件中记录的行数
3.开始读,写,并且记录传输进度
4.通过painc()模拟断电,继续传输
这里遇到个大坑 排查半天,那就是open.file的第三个参数,777和os.ModePerm不一样,要写成0777才可以.
func main() {
//逻辑 源文件读完,写到目标文件,写的时候记录光标的位置数到临时文件,中间断电,恢复后,继续断电前的光标位置传输
//1.设置源文件,目标文件,临时文件的路径
yuanwenjian := "E:\\Environment\\GoWorks\\src\\pojo\\xxx.png"
mubiaowenjian := "E:\\Environment\\GoWorks\\src\\xxxcopy.png"
linshiwenjian := "E:\\Environment\\GoWorks\\src\\pojo\\a.txt"
//建立流
file1, _ := os.Open(yuanwenjian)
file2, _ := os.OpenFile(mubiaowenjian, os.O_RDWR|os.O_CREATE, os.ModePerm) //写777就续传不上了
file3, _ := os.OpenFile(linshiwenjian, os.O_RDWR|os.O_CREATE, 0777)
defer file1.Close()
defer file2.Close()
//2.取临时文件中的数据
file3.Seek(0, 0) //将光标放到最开始
buf := make([]byte, 1024, 1024) //设置临时文件的缓冲区
n, err := file3.Read(buf) //读临时文件到buf,返回长度lin
fmt.Println(buf, err)
countstr := string(buf[:n]) //取buf从0到lin,并转为string类型
fmt.Println("countstr:", countstr)
//将countstr转为数字
count, _ := strconv.ParseInt(countstr, 10, 64)
//3.设置光标位置seek
file1.Seek(count, 0) //从count开始读
file2.Seek(count, 0) //从count开始写
bufData := make([]byte, 1024, 1024)
total := int(count)
//4.传输并记录进度到临时文件
for {
//读
readNum, err := file1.Read(bufData)
if err == io.EOF {
fmt.Println("读取完毕", err)
file3.Close()
os.Remove(linshiwenjian) //读取完毕销毁临时文件
break
}
//写
writeNum, _ := file2.Write(bufData[:readNum])
total = total + writeNum //最新行数total+写进去的行数
//将传输进度记录,先重置临时文件光标,在记录
file3.Seek(0, 0)
file3.WriteString(strconv.Itoa(total))
//模拟断电
/*if total > 1000 {
panic("断电了")
}*/
}
}
bufio
封装了io与缓冲区的包
func main() {
//创建流
file, _ := os.OpenFile("./pojo/b.txt", os.O_RDWR, os.ModePerm)
//bufio读,返回reader对象
reader := bufio.NewReader(file)
buf := make([]byte, 1024)
//用reader对象读
n, _ := reader.Read(buf)
fmt.Println(string(buf[:n]))
//读取键盘输入
newReader := bufio.NewReader(os.Stdin)
str, _ := newReader.ReadString('\n')
fmt.Println("键盘输入为", str)
//bufio写
writer := bufio.NewWriter(file)
writeString, _ := writer.WriteString("hahahh")
fmt.Println(writeString) //6
//发现并没有写进去文件原因是缓冲区大小是1024,没有满
//手动将缓冲区数据,写入文件
writer.Flush()
}
手写递归文件夹
func main() {
address := "E:\\Environment\\GoWorks\\src"
list(address, 0)
}
// 传入地址,和层级,初始为0级
func list(address string, tabint int) {
//表示层级关系的符合,每次增加层级tab就增加
tab := "|--"
for i := 0; i < tabint; i++ {
tab = "| " + tab
}
//os.Reader()方法,读文件夹,返回指针和err
dir, _ := os.ReadDir(address)
//forr返回2个,一个貌似是计数,,一个是文件对象
for _, file := range dir {
//拼接文件对象的名字
filename := address + "\\" + file.Name()
fmt.Printf("%s%s\n", tab, filename)
//如果是文件夹,继续递归这个方法,并且层级加1,拼接的名字对象也会变长.
if file.IsDir() {
list(filename, tabint+1)
}
}
}