golang学习之六:中的文件操作

文件的分类和作用

因为我们要操作文件,那首先明白文件的分类和作用

  • 设备文件

     屏幕(标准输出设备)fmt.Println()   往标准输出设备写内容
     键盘(标准输入设备)fmt.scan()  从标准输入设备读取内容
    
  • 磁盘文件,放在存储设备上的文件

     1)文本文件。以记事本打开,能看到内容(不是乱码)
     2)二进制文件以记事本打开,能看到内容,
     如:以记事本打开一张.jpg的图片(是乱码)所以我们在操作图片、视频等文件的时候一般都是以二进制流去读取的。
     为什么需要文件?因为内存掉电丢失,
     程序结束,内存中的内容消失文件放磁盘,程序结束,文件还是存在
    

相关API

以下介绍的api均为os包下,大家可以用不同的包调用更多的api

建立与打开

新建文件可以通过如下两个方法:

1.如果文件不存在,就创建一个文件。如果文件存在,清空再创建,若不想清空, 可以调用Open方法。
2.根据提供的文件名创建新的文件,返回一个文件对象,
  默认权限是0666的文件,返回的文件对象是可读写的。
func Create(name string) (file *File, err Error)

根据文件描述符创建相应的文件,返回一个文件对象
func NewFile(fd uintptr, name string) *File


通过如下两个方法来打开文件:

该方法打开一个名称为name的文件,但是是只读方式,内部实现其实调用了OpenFile。
func Open(name string) (file *File, err Error)

1.打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
2.这个方法就牛掰了,大家可以看下源码,其实Create与Open底层调用的都是OpenFile
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)

写文件

1.写入byte类型的信息到文件
2.可以处理二进制(图片、视频等)和非二进制文件,就是能处理所有文件
func (file *File) Write(b []byte) (n int, err Error)

在指定位置开始写入byte类型的信息,其实就是从指定位置写入
func (file *File) WriteAt(b []byte, off int64) (n int, err Error)

1.写入string信息到文件
2.专门处理文本文件的
func (file *File) WriteString(s string) (ret int, err Error)

读文件

1.读取数据到b中,返回值为它读取的长度
func (file *File) Read(b []byte) (n int, err Error)

从off开始读取数据到b中,其实就是从指定位置读
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)

删除文件

果然啊,创建与打开文件的api有一大堆,但删除文件的api只有一个。就像
命(ming四声)死(si三声)没有同音字一样,命只有一条,只能死一次。

调用该函数就可以删除文件名为name的文件
func Remove(name string) Error

示例代码

写文件

不比比,上代码

package main

import (
	"fmt"
	"os"
)

func WriteFile(path string) {
	file, err := os.Create(path)
	fmt.Println("create file fail")

	if err != nil {
		fmt.Println("create file fail :%s", err.Error())
		return
	}

	// 使用完毕,需要关闭文件
	defer file.Close()

	var buf string
	for i := 0; i < 10; i++ {
		// 将 i = 1\n 这个字符串存储在buf当中
		buf = fmt.Sprintf("i = %d\n", i)
		fmt.Println("buf = %s", buf)
		n, err := file.WriteString(buf)
		if err != nil {
			fmt.Println("WriteString fail :%s", err.Error())
		}
		fmt.Println("n = ", n)
	}
}

func main() {
	// 在当前路径下创建一个文件
	path := "./xxx.txt"
	WriteFile(path)
}

在当前路径下,文件依然存在
在这里插入图片描述

读文件

不比比,上代码

按二进制流读取文件

二进制流可以读取一切文件

package main

import (
	"fmt"
	"io"
	"os"
)

func WriteFile(path string) {
	file, err := os.Create(path)
	fmt.Println("create file fail")

	if err != nil {
		fmt.Println("create file fail :%s", err.Error())
		return
	}

	// 使用完毕,需要关闭文件
	defer file.Close()

	var buf string
	for i := 0; i < 10; i++ {
		// 将 i = 1\n 这个字符串存储在buf当中
		buf = fmt.Sprintf("i = %d\n", i)
		fmt.Println("buf = %s", buf)
		n, err := file.WriteString(buf)
		if err != nil {
			fmt.Println("WriteString fail :%s", err.Error())
		}
		fmt.Println("n = ", n)
	}
}

func ReadFile(path string) {
	file, err := os.Open(path)
	if err != nil {
		fmt.Println("readFile fail err=", err.Error())
		return
	}
	// 关闭文件
	defer file.Close()

	buf := make([]byte, 1024*2) // 2k大小

	// n代表从文件读取内容的长度
	n, err1 := file.Read(buf)
	// 文件出错,同时没有到结尾
	if err1 != nil && err1 != io.EOF {
		fmt.Println("fileRead fail err=", err1.Error())
		return
	}
	// 这里为啥是n,假设文件长度1024,然后你只读了1024,但是buf定义的长度为2048,所以这里按照实际的来
	fmt.Println("buf =", string(buf[:n]))
}

func main() {
	// 在当前路径下创建一个文件
	path := "./xxx.txt"
	WriteFile(path)
	ReadFile(path)
}

控制台

buf = i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

上面读文本文件没啥问题,但是java用习惯了,有没有按行来读文本文件呢?

按行读取文本文件

如果按行读取的话,我们就需要另一个包了,它是带缓存的io,bufio

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func WriteFile(path string) {
	file, err := os.Create(path)
	fmt.Println("create file fail")

	if err != nil {
		fmt.Println("create file fail :%s", err.Error())
		return
	}

	// 使用完毕,需要关闭文件
	defer file.Close()

	var buf string
	for i := 0; i < 10; i++ {
		// 将 i = 1\n 这个字符串存储在buf当中
		buf = fmt.Sprintf("i = %d\n", i)
		fmt.Println("buf = %s", buf)
		n, err := file.WriteString(buf)
		if err != nil {
			fmt.Println("WriteString fail :%s", err.Error())
		}
		fmt.Println("n = ", n)
	}
}

func ReadFile(path string) {
	file, err := os.Open(path)
	if err != nil {
		fmt.Println("readFile fail err=", err.Error())
		return
	}
	// 关闭文件
	defer file.Close()

	buf := make([]byte, 1024*2) // 2k大小

	// n代表从文件读取内容的长度
	n, err1 := file.Read(buf)
	// 文件出错,同时没有到结尾
	if err1 != nil && err1 != io.EOF {
		fmt.Println("fileRead fail err=", err1.Error())
		return
	}
	// 这里为啥是n,假设文件长度1024,然后你只读了1024,但是buf定义的长度为2048,所以这里按照实际的来
	fmt.Println("buf =", string(buf[:n]))
}

func ReadFileLine(path string) {
	fmt.Println("=====================================================")
	file, err := os.Open(path)
	if err != nil {
		fmt.Println("readFile fail err=", err.Error())
		return
	}
	// 关闭文件
	defer file.Close()

	r := bufio.NewReader(file)
	for {
		//
		// 因为我们写文件的时候是以\n结束的,遇到\n结束读取,但是它会把\n也读取出来,就是你读取的结果也会被\n
		buf, err := r.ReadBytes('\n')
		if err != nil {
			// 文件已结束
			if err == io.EOF {
				break
			}
			// 如果是其他错误,这里我们直接打印错误信息
			fmt.Println("err=", err.Error())
		}
		// 大家看打印结果可以看到,这里的%s与后面的#号之间我们是没有换行的但是,控制台是换行的
		// 由此可鉴r.ReadBytes('\n')它会把\n也读取出来,就是你读取的结果也会被\n
		fmt.Printf("buf = #%s#\n", string(buf))
		//fmt.Printf("buf = %s", string(buf))
	}
}

func main() {
	// 在当前路径下创建一个文件
	path := "./xxx.txt"
	WriteFile(path)
	//ReadFile(path)
	ReadFileLine(path)
}

控制台

buf = #i = 0
#
buf = #i = 1
#
buf = #i = 2
#
buf = #i = 3
#
buf = #i = 4
#
buf = #i = 5
#
buf = #i = 6
#
buf = #i = 7
#
buf = #i = 8
#
buf = #i = 9
#

又快到凌晨12点了,眼睛有点扛不住了,酸涩…

小练习:拷贝文件

不比比,眼睛快受不了了,直接上代码

package main

import (
	"fmt"
	"io"
	"os"
)

// "F:\xxx.jpg"
func main() {
	// 获取控制台的命令行参数
	list := os.Args
	// 因为我们这里设置的就是3个参数的形式,所以不足三个参数,其实是输入不合法,直接返回
	if len(list) != 3 {
		fmt.Println("usage: xxx srcFile dstFile")
		return
	}

	srcFileName := list[1]
	dstFileName := list[2]
	if srcFileName == dstFileName {
		fmt.Println("源文件与目的文件名字不能相同")
		return
	}

	// 只读方式打开源文件
	srcFile, err1 := os.Open(srcFileName)
	if err1 != nil {
		fmt.Println("err1 = ", err1)
		return
	}

	// 新建目的文件
	dstFile, err2 := os.Create(dstFileName)
	if err1 != nil {
		fmt.Println("err2 = ", err2)
		return
	}

	// 操作完需要关闭文件
	defer srcFile.Close()
	defer dstFile.Close()

	// 核心内容:从源文件读取内容,向新文件写,读多少写多少
	buf := make([]byte, 4*1024) // 4k大小临时缓冲区
	for {
		// 从源文件读取内容
		n, err := srcFile.Read(buf)
		if err != nil {
			// 文件读取完毕
			if err == io.EOF {
				break
			}
			fmt.Println("文件读取完毕:err = %s", err)
		}
		// 往目的文件写,都多少写多少
		dstFile.Write(buf[:n])
	}
}

运行,我们先把go文件编译为,可执行文件,再运行命令符

// 编译为可执行文件
PS D:\vscode\code\demo1> go build copy_file.go  
PS D:\vscode\code\demo1>.\copy_file.exe F:\xxx.jpg F:\yyy.jpg  

执行完go build copy_file.go会在go文件同级目录生成一个exe文件
在这里插入图片描述

这里解释以下,我的系统是win11(破玩意自己升级的不能取消,升级后,我就把window update服务禁用了)
直接运行copy_file.exe F:\xxx.jpg F:\yyy.jpg,我的会遇到问题,报错:

Suggestion [3,General]: 找不到命令 copy_file.exe,但它确实存在于当前位置。默认情况下,Windows PowerShell 不会从当前位置加载命令。如果信任此命令,请改为键入“.\copy_file.exe”。 有关详细信息,请参阅 "get-help about_Command_Precedence"

改成.\copy_file.exe就行了。
文件顺利复制。

在这里插入图片描述

请添加图片描述
星爷:为什么坚持,想一想当初。

每天看11个小时的电脑,眼睛受不了了,溜了,溜了

个人学习笔记,不喜勿喷

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值