likes
comments
collection
share

(二)常用内置函数

作者站长头像
站长
· 阅读数 26

文件系统

当前文件偏移量【指针】 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