文件的分类和作用
因为我们要操作文件,那首先明白文件的分类和作用
-
设备文件
屏幕(标准输出设备)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个小时的电脑,眼睛受不了了,溜了,溜了
个人学习笔记,不喜勿喷