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("拷贝完成")
}

自己查文档实现遍历文件夹

  • 例如:给一个文件夹路径, 获取该文件夹下所有文件,并将所有文件路径保存到切片中