文件系统
当前文件偏移量【指针】 Current Offset
当打开或者创建一个文件时,都会有文件偏移量,用以度量从文件开始处计算的字节数,通常,读,写操作都是从当前文件偏移量开始,并使偏移量增加所读写的字节数.按照系统默认情况,当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0
文件读取完毕后指针会指向文件尾部,此时再进行读取是读不到东西的
io.Copy(dst io.Writer, src io.Reader) (written int64, err error)
接受两个参数:一个可写源,一个可读源
func FileOperate() {
sourceFile, err := os.Open("./fileSys/demo.txt")
if err != nil {
fmt.Println(err)
}
targetFile, err := os.Create("./fileSys/demo1.txt")
targetFile2, err := os.Create("./fileSys/demo2.txt")
io.Copy(targetFile, sourceFile) // 成功将demo.txt的内容复制到了demo1
io.Copy(targetFile2, sourceFile) // 没有复制到任何东西
}
上面的代码,执行过一次Copy后,sourceFile的指针指向文件尾部,再进行赋值,读取不到任何内容了,想要继续copy到内容,需要将文件指针指向文件头部:
...
...
io.Copy(targetFile, sourceFile)
sourceFile.Seek(0,io.SeekStart) // 将文件指针移到头部
io.Copy(targetFile2, sourceFile)
// 或者调用os.Open()再次打开文件
File.ReadFrom(r io.Reader) (n int64, err error)
将读取的数据写入到文件中,和io.Copy类似,io.Copy内部一般也是调用此方法,进行操作
func FileOperate() {
sourceFile, err := os.Open("./fileSys/demo.txt")
if err != nil {
fmt.Println(err)
}
targetFile, err := os.Create("./fileSys/demo1.txt")
targetFile2, err := os.Create("./fileSys/demo2.txt")
targetFile.ReadFrom(sourceFile)
sourceFile.Seek(0, io.SeekStart)// 指针重置到文件头部
targetFile2.ReadFrom(sourceFile)
}
File.ReadAt(b []byte, off int64) (n int, err error)
从文件off指定偏移位置尝试读取n个字节长度的内从到切片b中,如果读取成功返回读取的长度n,失败返回err,这个方法不会自动更新文件的偏移量,下次读取依旧从指定的位置开始
File.Read(b []byte) (n int, err error)
从文件头部开始读取n个字节的内容到切片b中,如果读取成功返回读取的长度n,失败返回err,这个方法会自动更新文件偏移量,下一次将从上次一读取结束的地方开始
File.Write(b []byte) (n int, err error)
向文件中写入内容
// 同样以上面文件copy为例
func FileOperate() error {
sourceFile, err := os.Open("./fileSys/demo.txt")
if err != nil {
fmt.Println(err)
}
sourceFileInfo, err := sourceFile.Stat()
if err != nil {
return err
}
buffer := make([]byte, sourceFileInfo.Size())
sourceFile.Read(buffer)
targetFile, err := os.Create("./fileSys/demo1.txt")
targetFile2, err := os.Create("./fileSys/demo2.txt")
targetFile.Write(buffer)
targetFile2.Write(buffer)
return nil
}
- 上面方式读取大文件可能会有性能问题,换另一种方式:
func FileOperate() error {
sourceFile, err := os.Open("./fileSys/demo.txt")
if err != nil {
fmt.Println(err)
}
targetFile, err := os.Create("./fileSys/demo1.txt")
targetFile2, err := os.Create("./fileSys/demo2.txt")
buffer := make([]byte, 1024)
for {
n, err := sourceFile.Read(buffer)
if err != nil {
break
}
if n > 0 {
// 可能读不满1024个字节,所以要根据实际截取
targetFile.Write(buffer[0:n])
targetFile2.Write(buffer[0:n])
}
}
return nil
}
判断文件、目录是否存在
if file, err := os.Stat("./fileSys/asdf/demo45.txt"); err == nil || os.IsExist(err) {
fmt.Println("文件存在", file)
return
}
fmt.Println("文件不存在")
// 或者使用os.IsNotExist判断
其他内置函数
时间格式化
骚气的格式化方法,和js不同,不能用
YYYY-MM-DD HH:mm:ss
的形式,而是要传入一个指定格式实际日期模板,例如:2022-01-02 15:20:32
尤其注意时分秒格式化:时间模板
3
代表12小时制,15
代表24小时制
// 获取当前时间并格式化成指定日期(12小时制)
t := time.Now().Format("20060102_030405")
fmt.Println(t) // 输出:20230829_111650
// 获取当前时间并格式化成指定日期(24小时制)
t := time.Now().Format("20060102_150405")
fmt.Println(t) // 输出:20230829_111650