golang 文件处理

程序说白了就是不停的读取和写入文件的过程,所以文件的一些基本操作我们要清楚


前言

实际项目开发中我们少不了对配置文件进行读写操作,从而实现可配置化的项目,减少硬编码,那么文件的操作我们就必须得会。


一、读取大文件

需求:读取文件的内容,并显示在终端(带缓冲区的方式)

读取大文件一般都需要带缓冲区的方式

代码实现如下:

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
成功在文件中写入了内容

四、导出文件内容到新文件中

将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("文件导出完成!!!")
}

输出结果:

文件导出完成!!!

生成新文件csdn1
![在这里插入图片描述](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文件操作的内容,更多高级功能有待大家挖掘,感谢。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yezhijing

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

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

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

打赏作者

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

抵扣说明:

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

余额充值