Go_IO操作文件/目录

创建/删除目录

Go语言IO操作可以通过os包或bufio包,bufio是带缓冲的

创建目录:

  • os.Mkdir():创建单个目录,如果存在则失败

  • os.MkdirAll():创建多级目录,如果存在则不操作

nameperm
文件路径操作权限
func main() {
	// ModePerm = 0777  授最高权限,
	err := os.Mkdir("/Users/itzhuzhu/Desktop/笔记", os.ModePerm)
	if err != nil {
		fmt.Println("Mkdir创建目录失败:", err)
	} else {
		fmt.Println("Mkdir创建目录成功")
	}

	err = os.MkdirAll("/Users/itzhuzhu/Desktop/笔记/a/b/c", os.ModePerm)
	if err != nil {
		fmt.Println("MkdirAll创建目录失败:", err)
	} else {
		fmt.Println("MkdirAll创建目录成功")
	}
}

删除文件或目录

  • Remove:删除文件或空目录,不存在则报错
  • RemoveAll:删除文件或目录(包含所有子目录),不存在不操作
func main() {
	err := os.Remove("/Users/itzhuzhu/Desktop/笔记/test")
	if err != nil {
		fmt.Println("Remove删除目录失败:", err)
	} else {
		fmt.Println("Remove删除目录成功")
	}

	err = os.RemoveAll("/Users/itzhuzhu/Desktop/笔记/a")
	if err != nil {
		fmt.Println("RemoveAll删除目录失败:", err)
	} else {
		fmt.Println("RemoveAll删除目录成功")
	}
}

创建文件:

os.Create:文件不存在则创建,存在则删除文件中的内容,成为新文件,该函数本质上是在调用os.OpenFile()函数,

func main() {
  // 返回创建文件的指针
	file, err := os.Create("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println("创建失败  ", err)
	}
	fmt.Println("创建成功  ")
	defer file.Close()
}

打开文件:

os.OpenFile():打开文件,OpenFile有三个参数:

  • name:打开文件的路径
  • flag:模式,常见的模式有
参数说明
O_RDONLY只读方式打开
O_WRONLY只写方式打开
O_RDWR读写方式打开
O_APPEND追加方式打开
O_CREATE不存在,则创建
O_EXCL如果文件存在,且标定了O_CREATE的话,则产生一个错误
O_TRUNC如果文件存在,且它成功地被打开为只写或读写方式,将其长度裁剪唯一(覆盖)
O_NOCTTY如果文件名代表一个终端设备,则不把该设备设为调用进程的控制设备
O_NONBLOCK如果文件名代表一个FIFO,或一个块设备,字符设备文件,则在以后的文件及I/O操作中置为非阻塞模式
O_SYNC当进行一系列写操作时,每次都要等待上次的I/O操作完成再进行
  • perm:表示权限,取值范围(0-7),和linux里操作文件那个权限一样,如果是用OpenFile打开目录写os.ModeDir

0:没有任何权限
1:执行权限(如果是可执行文件,是可以运行的)
2:写权限
3:写权限与执行权限
4:读权限
5:读权限与执行权限
6:读权限与写权限
7:读权限,写权限,执行权限

演示:

func main() {
	file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/test.txt", os.O_RDWR, 6)
	if err != nil {
		fmt.Println("打开失败", err)
	}
	fmt.Println("打开成功")
	defer file.Close()
}

使用Open也可以打开文件,Open底层调用的是OpenFile方法,但是参数是写死了(只读模式),源码如下

func Open(name string) (*File, error) {
	return OpenFile(name, O_RDONLY, 0)
}

读数据:

Read:一次读全部数据,os.Read(读取后存放的切片)

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println("打开文件失败:", err)
	}
	defer file.Close()

	// 定义一个切片存储文件读取的数据
	buffer := make([]byte, 1024)

	// len:返回读到数据的字节(文件大小)
	len, err := file.Read(buffer)
	if err != nil {
		fmt.Println("读取数据失败:", err)
	}
	fmt.Println("读到:", len, "字节")
	fmt.Println("内容为:", string(buffer)) // 将读到的字节数据转换为string才可以展示出内容
}

ReadFile:读数据更方便,不需要先用Open打开文件,底层调用了Open会自动完成

func main() {
	readFile, _ := os.ReadFile("/Users/itzhuzhu/Desktop/笔记/test.txt")
	fmt.Println(string(readFile))
}

ReadDir读目录:

func main() {
	file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记", os.O_RDONLY, os.ModeDir)
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	// 参数:要获取的目录数,全部为负数,通常写-1
	dirAll, _ := file.ReadDir(-1)
	for _, name := range dirAll {
		if name.IsDir() {
			fmt.Println("目录:", name.Name())
		} else {
			fmt.Println("文件:", name.Name())
		}
	}
}

写数据:

Write:一次写入全部数据:

func main() {
	file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/test.txt", os.O_RDWR, 6)
	if err != nil {
		fmt.Println("打开失败:", err)
	}

	str := "我是写进去的数据"
	len, err := file.WriteString(str)
	if err != nil {
		fmt.Println("写入失败:", err)
	}
	fmt.Println("写入成功,长度为:", len, "字节")
	defer file.Close()
}

WriteString:底层调用了Write做了数据转换,参数不需要转字节切片就可以使用

func main() {
	file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/test.txt", os.O_RDWR, 6)
	if err != nil {
		fmt.Println("打开失败:", err)
	}

	str := "我是写进去的数据"
	len, err := file.WriteString(str)
	if err != nil {
		fmt.Println("写入失败:", err)
	}
	fmt.Println("写入成功,长度为:", len, "字节")
	defer file.Close()
}

WriteAt写数据:在指定的位置写入数据

方法参数返回值
func (f *File) Seek(offset int64, whence int) (ret int64, err error)offset:偏移量(空格数)
whence:从哪里开始偏移
SeekStart = 0 // 文件的开头
SeekCurrent = 1 // 当前数据的位置
SeekEnd = 2 // 文件的末尾
偏移量长度

Seek:设置下一次读/写的起始的偏移量(位置)

func main() {
	path := "/Users/itzhuzhu/Desktop/笔记/test.txt"
	file, err := os.OpenFile(path, os.O_RDWR, 6)
	if err != nil {
		fmt.Println("打开失败:", err)
	}
	defer file.Close()

	str := "我是WriteAt在指定位置写入的数据"

	/*
		whence:从哪里开始偏移
				SeekStart   = 0 // 文件的开头,会从头覆盖原数据,直到将新数据全部写完
				SeekCurrent = 1 // 当前数据的位置
				SeekEnd     = 2 // 文件的末尾
	*/

	num, err := file.Seek(0, 1)

	/*
		参数1:要写的数据
		参数2:是要写入数据的开始索引,上面引用了io.SeekEnd可以计算出原数据的长度,然后就可以在原数据基础上追加数据,如果写0会从0索引覆盖原数据
		返回值1:写入的字符长度
		返回值2:异常信息
	*/

	len, err := file.WriteAt([]byte(str), num)
	if err != nil {
		fmt.Println("写入失败:", err)
	}
	fmt.Println("共写入数据:", len, "字节")
}

缓冲区读数据:

缓冲区的设计是为了减少读/写大量数据带来的内存开销,先把数据读/写到缓冲区,然后由缓冲区写入系统。当发起一次读写操作时,计算机会先从缓冲区获取数据,如果当缓冲区数据为空,才会从数据源获取数据更新到缓冲区。

方法作用
func NewReader(rd io.Reader) *Reader创建一个具有默认大小的缓冲区,底层调用了NewReaderSize
func NewReaderSize(rd io.Reader, size int) *Reader创建一个具有4096字节的缓冲区
func (b *Reader) ReadBytes(delim byte) ([]byte, error)1次读1个字节
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)1次读1行,由\n分割
func (b *Reader) ReadRune() (r rune, size int, err error)1次读1个字符
func (b *Reader) ReadString(delim byte) (string, error)1次读1个字符串

NewReaderSize读数据

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	// 读数据,定义一个切片存储文件读取的数据
	r := bufio.NewReaderSize(file, 4096)

	// 按行读数据,ReadBytes(遇到则停止的字符)
	for {
		buf, err := r.ReadBytes('\n')
    // 先打印已读到的数据
		fmt.Print(string(buf))
    // 遇到\n继续读下一行
		if err == io.EOF {
			return
		}
	}
}

NewReader读数据

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
  // 底层调用了NewReaderSize,默认大小是4096
	r := bufio.NewReader(file)
}

使用ReadLine读数据,缓冲区读数据会判断最后返回的有么有EOF,如果没有就继续读,如果有就结束,所以会多读一次。

ReadLine底层调用了ReadSlice,ReadSlice会判断是否遇到\n,如果

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	r := bufio.NewReaderSize(file, 4096)
	i := 0
	for {
		// line:读到的数据
		i++
		line, _, err := r.ReadLine()
		fmt.Println("第", i, "次读数据\t", "大小为:", len(line))
		fmt.Println("数据:", string(line))
		if err == io.EOF {
			return
		}
	}
}

输出:

1 次读数据    大小为: 3
数据: 12 次读数据    大小为: 1
数据: 23 次读数据    大小为: 1
数据: 34 次读数据    大小为: 1
数据: 35 次读数据    大小为: 0
数据:

使用ReadRune读数据

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	r := bufio.NewReaderSize(file, 4096)

	for {
		// size:读到的大小
		readRune, _, err := r.ReadRune()
		fmt.Print(string(readRune))
		if err == io.EOF {
			return
		}
	}
}

ReadString读数据

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	r := bufio.NewReaderSize(file, 4096)

	for {
		readString, err := r.ReadString('\n')
		fmt.Print("数据为:", string(readString))
		if err == io.EOF {
			return
		}
	}
}

Scanner读数据

方法作用
func NewScanner(r io.Reader) *Scanner自带缓冲区的读数据方法,大小为4096,默认按行分割
func (s *Scanner) Scan() bool指定读取分割的方式

Split函数分割的方式:

方法作用
ScanBytes按字节分割
SacanLines按行分割
SacanRunes按UTF-8字符分割
SacanWords按单词分割

演示:

func main() {
	file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println("打开文件失败:", err)
	}
	defer file.Close()

	// 创建读数据缓冲
	reader := bufio.NewReader(file)
	// 创建Scanner对象
	scanner := bufio.NewScanner(reader)
	// 指定按行读
	scanner.Split(bufio.ScanLines)
	// 循环读取
	for scanner.Scan() {
		// 打印读到的数据
		fmt.Println(string(scanner.Bytes()))
		fmt.Println(scanner.Text())
	}
}

缓冲区写数据:

方法作用
func NewWriter(w io.Writer) *Writer创建一个具有默认大小的缓冲区,底层调用了NewReaderSize
func NewWriterSize(w io.Writer, size int) *Writer创建一个具有4096字节的缓冲区
func (b *Writer) Flush() error清空缓冲区并将数据写入
func (b *Writer) WriteByte(c byte) error1次写1个字节
func (b *Writer) WriteRune(r rune) (size int, err error)1次写1个字符
func (b *Writer) WriteString(s string) (int, error)1次写1个字符串

NewWriter写数据

func main() {
	readPath := "/Users/itzhuzhu/Desktop/笔记/test.txt"
	writerPath := "/Users/itzhuzhu/Desktop/笔记/test2.txt"

	// 打开要读的文件
	readFile, err := os.Open(readPath)
	if err != nil {
		fmt.Println(err)
	}
	defer readFile.Close()

	// 创建读缓冲区
	reader := bufio.NewReader(readFile)

	// 打开要写的文件
	writerFile, err := os.OpenFile(writerPath, os.O_RDWR, 6)
	if err != nil {
		fmt.Println(err)
	}
	defer writerFile.Close()

	// 创建写缓冲区
	writer := bufio.NewWriter(writerFile)

	// 循环读数据
	for {
		bytes, err := reader.ReadBytes('\n')
		// 读到了就写到写缓冲区
		writer.Write(bytes)
		// 清空缓冲区,并将缓冲区的数据写到文件
		writer.Flush()
		if err == io.EOF {
			break
		}
	}
}

文件权限:

例:- rwx rwx rwx权限用八进制表示为:0777

位置含义
第1位文件类型(d:目录 -:文件)
第2 ~ 4位u:所属用户权限
第5 ~ 7位g:所属组权限
第8 ~ 10位o:其他用户权限

权限使用数字表示:

权限八进制数字
r4
w2
x1
-0

filepath:

方法作用
func IsAbs(path string) bool是否绝对路径
func Split(path string) (dir, file string)分割为目录和文件名
func Join(elem …string) string将多个字符拼接成路径
func Ext(path string) string返回拓展名,如果是目录则为空
func Base(path string) string返回路径中最后一个元素
func Dir(path string) string返回是目录的路径
func ToSlash(path string) string将路径分隔符替换为/

演示:

func main() {
	path := "/Users/itzhuzhu/Desktop/笔记/test.txt"
	str := "aaa"

	fmt.Println("是否绝对路径:", filepath.IsAbs(path))
  
	dir, file := filepath.Split(path)
	fmt.Println("目录名:", dir, "\t文件名:", file)
  
	fmt.Println("多个字符拼接成路径", filepath.Join(path, str))

	ext := filepath.Ext(path)
	fmt.Println("拓展名为", ext) // 如果是目录结果为空

	base := filepath.Base(path)
	fmt.Println("路径中最后一个元素为:", base)

	s := filepath.Dir(path)
	fmt.Println("目录部分为:", s)

	slash := filepath.ToSlash(path)
	fmt.Println("将路径分隔符替换为/", slash)
}

输出:

是否绝对路径: true
目录名: /Users/itzhuzhu/Desktop/笔记/  文件名: test.txt
多个字符拼接成路径 /Users/itzhuzhu/Desktop/笔记/test.txt/aaa
拓展名为 .txt
路径中最后一个元素为: test.txt
目录部分为: /Users/itzhuzhu/Desktop/笔记
将路径分隔符替换为/ /Users/itzhuzhu/Desktop/笔记/test.txt

Stat

Stat可以查看文件属性

type FileInfo interface {
	Name() string       // 文件名称
	Size() int64        // 文件大小(字节)
	Mode() FileMode     // 文件权限
	ModTime() time.Time // 修改时间
	IsDir() bool        // 是否为目录
	Sys() any           // 底层数据源,不知道这是干嘛的
}

演示:

func main() {
	path := "/Users/itzhuzhu/Desktop/笔记/test22.txt"
	stat, err := os.Stat(path)
	if err != nil {
		fmt.Println("路径错误:", err)
	}
	fmt.Println("文件名称:", stat.Name())
	fmt.Println("文件大小:", stat.Size(), "字节")
	fmt.Println("当前权限:", stat.Mode())
	fmt.Println("修改时间:", stat.ModTime())
	fmt.Println("是否为目录:", stat.IsDir())
	fmt.Println("底层数据源:", stat.Sys())
}

IsNotExist

判断文件是否存在

func main() {
	_, err := os.Stat("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if os.IsNotExist(err) {
		fmt.Println("文件不存在")
	} else {
		fmt.Println("文件存在")
	}
}

Copy

func main() {
	// 打开原数据文件
	oldFile, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
	if err != nil {
		fmt.Println("打开源文件失败", err)
	}
	defer oldFile.Close()

	// 打开新文件
	newFile, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/NewTest.txt", os.O_RDWR|os.O_CREATE, 0777)
	if err != nil {
		fmt.Println("打开新文件失败", err)
	}
	defer newFile.Close()
	// dst:新文件   str:源文件
	written, err := io.Copy(newFile, oldFile)
	if err != nil {
		fmt.Println("复制失败", err)
	} else {
		fmt.Println("复制成功,共", written, "字节")
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzhuzhu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值