程序说白了就是不停的读取和写入文件的过程,所以文件的一些基本操作我们要清楚
前言
实际项目开发中我们少不了对配置文件进行读写操作,从而实现可配置化的项目,减少硬编码,那么文件的操作我们就必须得会。
一、读取大文件
需求:读取文件的内容,并显示在终端(带缓冲区的方式)
读取大文件一般都需要带缓冲区的方式
代码实现如下:
import (
"bufio"
"fmt"
"io"
"os"
)
// ReadFile 读取文件内容
func ReadFile(fileName string) {
file, err := os.Open(fileName)
if nil != err {
fmt.Println("文件打开失败:", err)
}
fmt.Printf("file的类型是:%T,值为:%v\n", file, file)
defer file.Close()
// 创建一个带缓冲的reader
reader := bufio.NewReader(file)
// 循环输出内容
for {
// 一次读取一行,\n表示换行
str, err := reader.ReadString('\n')
fmt.Println(str)
// io.EOF 表示文件的结尾
if io.EOF == err {
break
}
}
fmt.Println("文件读取结束!!!")
}
func main() {
ReadFile("C:/test/test.txt")
}
测试文件中的内容如下:
file content:
hello golang
testfile
这是一个配置文件
输出结果:
file的类型是:*os.File,值为:&{0xc0000d0780}
file content:
hello golang
testfile
这是一个配置文件
文件读取结束!!!
二、小文件一次性读取
需求:将一个小文件一次性读取到内存中,并将内容打印到终端
读取小文件直接使用io/ioutil下的ReadFile
代码实现如下:
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
fileName := "C:/test/test.txt"
content, err := ioutil.ReadFile(fileName)
if nil != err {
log.Fatal(err)
}
// 由于content是[]byte,所以想要得到人类可识别的文字还需要强转
fmt.Printf("content的类型是:%T, 值为:%v\n", content, content)
fmt.Printf("强转后的内容为:%v\n", string(content))
}
输出结果:
content的类型是:[]uint8, 值为:[102 105 108 101 32 99 111 110 116 101 110 116 58 13 10 104 101 108 108 111 32 103 111 108 97 110 103 13 10 116 101 115 116 102 105
108 101 13 10 232 191 153 230 152 175 228 184 128 228 184 170 233 133 141 231 189 174 230 150 135 228 187 182]
强转后的内容为:file content:
hello golang
testfile
这是一个配置文件
三、写文件
需求一:创建一个新文件,并在文件中写入5句 hello, csdn
这里使用到os.OpenFile(name string, flag int, perm FileMode) (file *File, err error) 函数
函数中的flag是打开文件的模式,查看源码可知其模式如下:
// OpenFile中flag的底层支持.
// 并非所有的flag都可以在给定的系统上实现
const (
// O_RDONLY, O_WRONLY, or O_RDWR 这三个中必须指定其中的一个。
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 // 如果可能,打开时清空文件。
)
以上模式可以通过 ‘|’ 组合使用
函数中的FileMode是文件的权限,这个功能只在Linux系统或是Unix系统上生效,windows系统无效,具体有哪些模式,源代码如下:
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权限位(用于通过&获取类型位)
)
代码实现如下:
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// 定义文件存放路径
fileName := "C:/test/csdn.txt"
// 以创建新文件和写的模式打开文件,由于底层系统是windows不支持FileMode
// 所以这里的FileMode是随意写的
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, 0777)
if nil != err {
log.Fatal(err)
}
defer file.Close()
fmt.Printf("file的类型是:%T,值为:%v\n", file, file)
// 这里我们使用带缓冲的writer将数据写入到文件中
writer := bufio.NewWriter(file)
fmt.Printf("writer的类型是:%T,值为:%v\n", writer, writer)
// 准备写入的语句
str := "hell, csdn \n"
for i := 0; i < 5; i++ {
writer.WriteString(str)
}
// 由于writer是带缓冲的,所以目前我们只是将数据写入到缓冲中了
// 想要让数据写入文件,我们还需要将缓冲中的数据刷到文件上
writer.Flush()
fmt.Println("文件写入结束!!!")
}
运行结果:
file的类型是:*os.File,值为:&{0xc0000d0780}
writer的类型是:*bufio.Writer,值为:&{<nil> [0 0 0 ... 0] 0 0xc0000ce018}
文件写入结束!!!
四、导出文件内容到新文件中
将csdn.txt中的内容导出到csdn1.txt中
这里我们直接使用ioutil下的ReadFile和WriteFile,新文件会自动创建
代码实现如下:
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
fileName1 := "C:/test/csdn.txt"
fileName2 := "C:/test/csdn1.txt"
data, err := ioutil.ReadFile(fileName1)
if nil != err {
log.Fatal(err)
}
err = ioutil.WriteFile(fileName2, data, 0777)
if nil != err {
log.Fatal()
}
fmt.Println("文件导出完成!!!")
}
输出结果:
文件导出完成!!!
![在这里插入图片描述](https://img-blog.csdnimg.cn/3edd2e3657014d1890c688cb272dd764.png#pic_center
五、判断文件是否存在
需求:判断csdn1.txt 与 csdn3.txt两个文件是否存在,判断test2和test目录是否存在
利用 os.Stat() 与 os.IsNotExist()组合来实现
代码实现如下(以下PathExists(path string)代码可以直接做为工具):
package main
import (
"fmt"
"log"
"os"
)
// PathExists 判断文件或目录是否存在
func PathExists(path string) (bool, error) {
// 返回一个FileInfo及err,这里我们不需要FileInfo
// 只需要通过err来判断
_, err := os.Stat(path)
if nil == err { // 表示文件或目录存在
return true, nil
}
if os.IsNotExist(err) { // 判断是否是不存在的错误
return false, nil
}
// 其它未知错误直接返回false和err
return false, err
}
func main() {
// 定义文件存放路径
fileName1 := "C:/test/csdn1.txt"
fileName2 := "C:/test/csdn3.txt"
path1 := "C:/test1"
path2 := "C:/test"
exist1, err := PathExists(fileName1)
if nil != err {
log.Fatal(err)
}
exist2, err := PathExists(fileName2)
if nil != err {
log.Fatal(err)
}
exist3, err := PathExists(path1)
if nil != err {
log.Fatal(err)
}
exist4, err := PathExists(path2)
if nil != err {
log.Fatal(err)
}
fmt.Printf("csdn1.txt是否存在?%v\n", exist1)
fmt.Printf("csdn3.txt是否存在?%v\n", exist2)
fmt.Printf("目录test1是否存在?%v\n", exist3)
fmt.Printf("目录test是否存在?%v\n", exist4)
}
输出结果:
csdn1.txt是否存在?true
csdn3.txt是否存在?false
目录test1是否存在?false
目录test是否存在?true
六、拷贝文件(支持大文件)
需求:将test目录下的1.jpg文件再拷贝一份并命名为6.jpg
如下图,目录下现有一个1.jpg的图片:
代码实现如下(以下CopyFile(distFileName string, srcFileName)函数可以直接作为工具使用):
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
)
// CopyFile 拷贝文件(支持大文件)
func CopyFile(distFileName string, srcFileName string) (written int64, err error) {
// 打开文件
srcFile, err := os.Open(srcFileName)
if nil != err {
fmt.Println("打开源文件失败:", err)
return 0, err
}
// 程序结束后及时关闭文件句柄
defer srcFile.Close()
// 使用带缓冲的形式读取内容
srcReader := bufio.NewReader(srcFile)
// 打开目标位置,不存在则创建
distFile, err := os.OpenFile(distFileName, os.O_WRONLY|os.O_CREATE, 0777)
if nil != err {
fmt.Println("打开目标文件失败:", err)
return 0, err
}
defer distFile.Close()
// 使用带缓冲的writer
writer := bufio.NewWriter(distFile)
return io.Copy(writer, srcReader)
}
func main() {
srcFileName := "C:/test/1.jpg"
distFileName := "C:/test/6.jpg"
_, err := CopyFile(distFileName, srcFileName)
if nil != err {
log.Fatal(err)
}
fmt.Println("拷贝完成!!!")
}
输出结果:
拷贝完成!!!
总结
以上就是本次分享的golang文件操作的内容,更多高级功能有待大家挖掘,感谢。