文件在程序中是以流的形式来操作的


Golang学习(二十五)文件操作_开发语言 


 在GO语言中有个OS包是专门用来对文件做操作的,打开官方文档


 Golang学习(二十五)文件操作_开发语言_02


找到type file 结构体,这个结构体下定义了大量针对文件操作的方法


 Golang学习(二十五)文件操作_缓存_03

一、读取文件

1、打开、关闭文件

#打开文件
func Open(name string) (file *File, err error)


#关闭文件
func (f *File) Close() error

案例

package main

import (
"fmt"
"os"
)

func main() {
file ,err:= os.Open("/root/11.txt")
//概念说明 file的叫法
//1、 file 叫 文件对象
//2、 file 叫 文件句柄
//3、 file 叫 文件指针
//这些都是一个意思
if err != nil {
//如果err值不为空说明打开失败了
fmt.Println("打开文件失败")
}
fmt.Printf("%v",file) //指针类型


err = file.Close()
if err != nil {
//如果err值不为空说明打开失败了
fmt.Println("关闭失败失败",err)
}
}

如果没有打开的返回值

#打开文件失败 
open /root/111.txt: The system cannot find the file specified.


#没有打开,无法关闭
<nil>关闭失败失败 invalid argument

2、读取文件内容并显示在终端

package main

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

func main() {
file ,err:= os.Open("E:/tar/11.txt")
if err != nil {
fmt.Println("打开文件失败")
}

defer file.Close() //当函数退出时,要及时关闭file句柄,否则会有内存泄露



reader := bufio.NewReader(file) //func NewReader(rd io.Reader) *Reader
//NewReader创建一个具有默认大小缓冲区
//默认缓存区为4096字节,在*Reader中可以查看代码
//缓冲的好处: 读一部分,处理一部分,用于处理大文件

for {


str,err := reader.ReadString('\n') //读取文件内容,读到一个\n换行就结束

if err == io.EOF{ //io.EOF表示文件末尾,说明读取文件结束了,break结束就行
break
}
fmt.Print(str)

}
fmt.Println("文件读取结束")
}

3、一次性读取文件(不带缓存)


读取整个文件到内存,使用ioutil包,适用于文件较小的场景


package main

import (
"fmt"
"io/ioutil"
)

func main() {

file := "E:/tar/11.txt"
content,err := ioutil.ReadFile(file) //使用ioutil.ReadFile一次将文件读取到内存中
if err != nil{
fmt.Println("读取文件错误",err)
}


fmt.Print("%v",content) //[]byte
fmt.Print("%v",string(content)) //因为是切片,不能直接输出,要转换为string类型
}


我们没有显示的Open文件  因此也不需要显示的Close文件
因为文件的Open和Close被封装到ReadFile函数内部


二、创建文件


 创建文件,我们使用OS包中的OpenFile函数,如下图


Golang学习(二十五)文件操作_开发语言_04

func OpenFile(name string, flag int, perm FileMode) (file *File, err error)


#参数说明
name string //将内容写入到那个文件中去
flag int //文件打开模式
perm FileMode //文件权限

文件打开模式

const (
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 // 如果可能,打开时清空文件
)

文件权限(主要是linux用)

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权限位(用于通过&获取类型位)
)

1、创建文件 写入数据

package main

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

func main() {

filePath := "e:/tar/abc.txt" //设置创建的文件的路径

file,err := os.OpenFile(filePath,os.O_WRONLY | os.O_CREATE,0666)
//设置创建的这个文件的模式
//O_WRONLY 只读打开文件
//O_CREATE 如果没有该文件则进行创建
//0666 给linux操作系统用的,windows无效

if err != nil{ //判断是否打开操作成功
fmt.Println(err)
return
}
defer file.Close() //及时关闭file句柄,防止内存泄露




str := "hello Gardon\r\n" //准备要写入的数据
// \n表示换行 ,有一些编辑器只认\r 这里为了方便都写上


writer := bufio.NewWriter(file) //因为写入数据不固定,我们建立缓存区

for i :=0 ; i < 5 ; i++{
writer.WriteString(str) //写入数据到缓存
}

writer.Flush() //因为writer是带缓存的,当上面使用了writer.WriteString并没有写入到磁盘
//而是写入了缓存区,我们需要调用Flush()这个方法将缓存的数据写入到磁盘中去
}

2、打开已存在的文件--覆盖原先的数据--写入新数据

package main

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

func main() {
filePath := "e:/tar/abc.txt" //指定已经存在的文件

file,err := os.OpenFile(filePath,os.O_WRONLY | os.O_TRUNC,0666) //修改模式,变更为写入模式O_WRONLY和清除模式O_TRUNC
if err != nil{
fmt.Println(err)
return
}
defer file.Close()



str := "你好\r\n" //修改字符

writer := bufio.NewWriter(file)
for i :=0 ; i < 10 ; i++{ //修改输入次数,我们这里输入10此您好
writer.WriteString(str)
}
writer.Flush()
}


3、打开存在的文件追加文本(比如日志)

package main

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

func main() {

filePath := "e:/tar/abc.txt"
file,err := os.OpenFile(filePath,os.O_WRONLY | os.O_APPEND,0666) //修改模式O_APPEND 追加数据和写入搭配
if err != nil{
fmt.Println(err)
return
}
defer file.Close()



str := "ABC\r\n" //修改字符

writer := bufio.NewWriter(file)
for i :=0 ; i < 1 ; i++{ //修改输入次数
writer.WriteString(str)
}

writer.Flush()
}


5、打开一个文件将原来的内容读取输出然后追加5句hello 北京

package main

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

func main() {

filePath := "e:/tar/abc.txt"
file,err := os.OpenFile(filePath,os.O_RDWR | os.O_APPEND,0666) //修改模式 O_RDWR读写模式
if err != nil{
fmt.Println(err)
return
}
defer file.Close()

reader := bufio.NewReader(file) //大量的读写操作都需要做缓存区
for {
str , err := reader.ReadString('\n') //上面案例有,读取整个文件的信息
if err == io.EOF{ //读取到文件末尾后退出
break
}
fmt.Println(str) //将读取到的每一行数据打印到终端
}


str := "hello 北京\r\n" //修改新增的字符

writer := bufio.NewWriter(file) //以缓存区模式去写入数据
for i :=0 ; i < 5 ; i++{ //修改输入次数
writer.WriteString(str)
}
writer.Flush()
}

6、文本内容转移

package main

import (
"fmt"
"io/ioutil"
)

func main() {
//将"e:/tar/abc.txt" 文件导入到D:/kkk.txt
//1 将"e:/tar/abc.txt"读取到内存
//2 将读取到的内容写入到D:/kkk.txt

file1Path := "e:/tar/abc.txt"
file2Path := "D:/kkk.txt"


data,err := ioutil.ReadFile(file1Path) //一次性读取文件
if err != nil{
fmt.Printf("read file err=%v",err)
return
}

err = ioutil.WriteFile(file2Path,data,0666) //通过ioutil.WriteFile将data数据写入到路径中
//写入的文件如果不存在,则会自动创建
if err != nil{
fmt.Printf("write file error=%v",err)
}
}

7、判断文件是否存在


通过os.Stat 检索文件


package main

import (
"fmt"
"os"
)


func PathExists(path string)(bool,error){
_, err := os.Stat(path)
if err == nil{ //文件或目录存在
return true,nil
}

if os.IsNotExist(err){ //如果os.lsNotExist(err)为true,说明文件不存在,返回false,和空
return false,nil
}

return false,err //如果上面都不满足,则输出原本的错误和信息
}


func main() {
file1Path := "e:/tar/abc.txt"

it,err := PathExists(file1Path)
if it{
fmt.Println("该文件/目录存在")
}else {
fmt.Println("该文件/目录不存在",err)
}
}

8、拷贝文件


通过IO包进行文件拷贝,支出拷贝大文件


//将一张图片拷贝到另一个目录下 io包
func Copy(dst Writer, src Reader) (written int64, err error)

//传参
Writer //目标文件路径
Reader //要拷贝的文件路径


//返回值
written //拷贝文件的字节大小
err //拷贝文件的错误信息

案例

package main

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

//我们这边写一个函数,接收要拷贝的路径,
func CopyFile(dstFileName string,srcFileName string)(written int64, err error){
srcfile,err := os.Open(srcFileName)
if err != nil{
fmt.Println("文件打开错误",err)
}
defer srcfile.Close()
reader := bufio.NewReader(srcfile) //将这个文件放到缓存区 读取模式 src


//我们拷贝过去的位置,这个文件不一定存在,我们就给他创建一下
dstfile,err := os.OpenFile(dstFileName,os.O_WRONLY | os.O_CREATE, 0666)
if err != nil{
fmt.Printf("open file err=%v",err)
return
}
defer dstfile.Close()
writer := bufio.NewWriter(dstfile) //给这个新建的文件以缓存模式打开 dest




//拷贝源文件到目标文件
return io.Copy(writer,reader) //通过上面的IO包的Copy模块将数据拷贝过去
}

func main(){
//将e:/tar/1.png 到d:/abc.png

//调用CopyFile 完成拷贝
srcFile := "e:/tar/1.png" //图片、视频、音乐等都可以用这种方法拷贝
dstFile := "d:/abc.png"
_,err := CopyFile(dstFile,srcFile)
if err == nil{
fmt.Println("拷贝完成")
}else{
fmt.Println("拷贝错误")
}

}

9、统计文件字符

package main

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

//定义一个结构体,用于保存结果
type CharCount struct{
ChCount int //记录英文的个数
NumCount int //记录数字的个数
SpaceCount int // 记录空格个数
OtherCount int // 用于记录其他字符
}

func main(){
fileName := "e:/tar/abc.txt"
file,err := os.Open(fileName)
if err != nil {
fmt.Println("open file error",err)
}
defer file.Close()


var count CharCount //声明结构体,用于统计各个字符的数量
reader := bufio.NewReader(file) //建立缓存区

for {
str,err := reader.ReadString('\n') //遍历读取每一行数据
if err == io.EOF{
break
}


for _, v := range str{ //将每一行数据for-range遍历每个字符
switch {
case v >= 'a' && v <= 'z' : //比较ASCLL码,因为他是一个byte数组,会打印一些100、97等数字
fallthrough //穿透处理,如果v在a到z之前会++,如果在A到Z直接也++
case v >= 'A' && v <= 'Z':
count.ChCount++
case v == ' ' || v== '\t': //如果是空格或者制表符的话,就在结构体+1
count.SpaceCount++
case v >= '0' && v <= '9':
count.NumCount++
default:
count.OtherCount++
}
}
}
fmt.Printf("字符的个数%v 数字的个数%v 空格的个数%v 其他字符%v",count.ChCount,count.NumCount,count.SpaceCount,count.OtherCount)
}

 返回

字符的个数28 数字的个数0  空格的个数5 其他字符62
进程 已完成,退出代码为 0