• Go 文件操作


    创建文件

    数据存储到文件之前,先要创建文件。GO语言中提供了一个Create()函数专门创建文件。

    该函数在创建文件时,首先会判断要创建的文件是否存在,如果不存在,则创建,如果存在,会先将文件中已有的数据清空。

    同时,当文件创建成功后,该文件会默认的打开,所以不用在执行打开操作,可以直接向该文件中写入数据。

    创建文件的步骤:

    1. 导入“os”包,创建文件,读写文件的函数都在该包。
    2. 指定创建的文件存放路径以及文件名。
    3. 执行Create()函数,进行文件创建。
    4. 关闭文件。

    具体代码如下:

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        //os.Create(文件名) 文件名  可以写绝对路径和相对路径
        //返回值  文件指针 错误信息
        fp,err := os.Create("./a.txt")
        if err!=nil{
            //文件创建失败
            /*
            1.路径不存在
            2.文件权限
            3.程序打开文件上限
             */
            fmt.Println("文件创建失败")
            return
        }
    
        //读写文件
    
        defer fp.Close()
    
        //关闭文件
        //如果打开文件不关闭 造成内存的浪费  程序打开文件的上限
        //fp.Close()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    执行以上代码后,可以在程序文件存放的目录中,看到有一个a.txt的文件。

    注意:在创建的文件时,注意需要判断是否出现异常,同时要注意defer的应用。

    写入数据

    文件打开以后,可以向文件中写数据,可以使用WriteString( )方法。

    //\反斜杠 转义字符
    	//在写路径时可以使用/正斜杠代替\反斜杠
    	fp, err := os.Create("a.txt")
    	if err != nil {
    		//文件创建失败
    		/*
    		   1.路径不存在
    		   2.文件权限
    		   3.程序打开文件上限
    		*/
    		fmt.Println("文件创建失败")
    		return
    	}
    
    	//写文件
    
    	//\n不会换行  原因 在windows文本文件中换行\r\n  回车  在linux中换行\n
    	fp.WriteString("hello world\r\n")
    	fp.WriteString("发牌")
    
    	defer fp.Close()
    
    	//关闭文件
    	//如果打开文件不关闭 造成内存的浪费  程序打开文件的上限
    	//fp.Close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    WriteString()方法默认返回两个参数:

    第一个参数,指的是写入文件的数据长度,第二个参数记录的是错误信息。

    WriteString()方法默认写到文件中的数据是不换行的。如果想换行,可以采用如下的方式:

    //\n不会换行 原因 在windows文本文件中换行\r\n 回车 在linux中换行\n
    fp.WriteString("hello world\r\n")
    fp.WriteString("性感荷官在线发牌")
    
    • 1
    • 2
    • 3

    除了使用WriteString()函数向文件中写入数据以外,还可以使用Write()函数,如下所示:

    fp,err := os.Create("D:/a.txt")
    if err!=nil{
        //文件创建失败
        /*
        1.路径不存在
        2.文件权限
        3.程序打开文件上限
         */
        fmt.Println("文件创建失败")
        return
    }
    
    //写操作
    //slice := []byte{'h','e','l','l','o'}
    //count,err1 := fp.Write(slice)
    count,err1 := fp.Write([]byte("性感老王在线授课"))
    
    if err1!=nil {
        fmt.Println("写入文件失败")
        return
    }else {
        fmt.Println(count)
    }
    
    defer fp.Close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里要注意的是,使用Write()函数写数据时,参数为字节切片,所以需要将字符串转换成字节切片。该方法返回的也是写入文件数据的长度。

    第三种写入的方式使用WriteAt()函数,在指定的位置写入数据:

    fp,err := os.Create("D:/a.txt")
    if err!=nil{
        //文件创建失败
        /*
        1.路径不存在
        2.文件权限
        3.程序打开文件上限
         */
        fmt.Println("文件创建失败")
        return
    }
    
    //写操作
    //获取光标流位置'
    //获取文件起始到结尾有多少个字符
    //count,_:=fp.Seek(0,os.SEEK_END)
    count,_:=fp.Seek(0,io.SeekEnd)
    fmt.Println(count)
    //指定位置写入
    fp.WriteAt([]byte("hello world"),count)
    fp.WriteAt([]byte("hahaha"),0)
    fp.WriteAt([]byte("秀儿"),19)
    
    defer fp.Close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    以上程序中Seek()函数返回值存储到变量n中,值为文件末尾的位置。WriteAt()也返回的是写入的数据长度。

    以上就是我们常用的关于向文件中写入数据的方式,但是有同学可能有疑问,每次向文件中写入数据之前,都是先执行了,Create()这个函数,而这个函数的作用前面我们也已经说过。有两个作用:

    第一:创建新文件。
    第二:如果所创建的文件已经存在,会删除掉文件中存储的数据。
    那么,现在怎样向已有的文件中追加数据呢?如果要解决这个问题,那么大家一定要注意的就是,对已经存在的文件不能再执行Create(),而是要执行OpenFile()。如下所示:

    //os.Open  只读方式打开
    //fp,err := os.Open("D:/a.txt")
    
    //os.OpenFile(文件名,打开方式,打开权限)
    fp,err := os.OpenFile("D:/a.txt",os.O_RDWR,6)
    if err!=nil {
        fmt.Println("打开文件失败")
    }
    
    fp.WriteString("hello")
    fp.WriteAt([]byte("hello"),25)
    
    
    defer fp.Close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    OpenFile()这个函数有三个参数,第一个参数表示打开文件的路径,第二个参数表示模式,常见的模式有

    O_RDONLY(只读模式),O_WRONLY(只写模式),O_RDWR(可读可写模式),O_APPEND(追加模式)。

    第三个参数,表示权限,取值范围(0-7)

    表示如下:

    1. 没有任何权限
    2. 执行权限(如果是可执行文件,是可以运行的)
    3. 写权限
    4. 写权限与执行权限
    5. 读权限
    6. 读权限与执行权限
    7. 读权限与写权限
    8. 读权限,写权限,执行权限

    读取文件

    一、 Read 读取文件
    如果文件已经存在,并且也已经有数据了,那么可以直接读取该文件中的内容。

    读取文件的基本流程如下:

    1. 打开要读取的文件
    2. 对文件进行读取
    3. 关闭文件

    在向文件中写数据的时候,使用的是Write,那么读取文件中的数据,使用的是Read。

    关于Read()函数的使用如下:

    ackage main
    
    import (
        "fmt"
        "io"
        "os"
    )
    func main() {
        //打开文件
        fp, err := os.Open("D:/a.txt")
        if err != nil {
            fmt.Println("err=", err)
            return
        }
    
        buf := make([]byte, 1024*2) //2k大小
        //n代表从文件读取内容的长度
        n, err1 := fp.Read(buf)
        if err1 != nil && err1 != io.EOF {
            fmt.Println("err1=", err1)
            return
        }
        fmt.Println("buf=", string(buf[:n]))
    
        //关闭文件
        defer fp.Close()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Open()是打开文件,与OpenFile()的区别是,Open()只有读的权限。

    在使用Read()函数读取文件中的内容时,需要一个切片类型,而定义切片时类型为字符数组,将文件中的内容保存在切片中,同时除了对其判断是否出错时以外,还要判断是否到文件末尾(这里需要导入io包)。

    Read()函数返回的是从文件中读取的数据的长度。最后,输出切片中存储的文件数据,注意,读取的是从最开始到整个数据长度,因为有可能存储到切片中的数据达不到切片的总长度(也是切片时2k,但是从文件中读取的数据有可能只有1k)。

    二、 按行读取
    上面我们是将文件的内容全部读取出来,然后存放在切片中,我们也可以每次只读取一行数据。

    这需要用到bufio包中的ReadBytes函数。具体如下:

    1. 打开文件

    fp, err := os.Open("D:/a.txt")
    if err != nil {
        fmt.Println("打开文件失败", err)
        return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 创建缓冲区
    在使用ReadBytes()函数读取数据时,需要用到缓冲区,所谓缓冲区就是存储数据的区域,也就是先将从文件中读取的数据存储在该区域内,然后在将区域中的数据取出来,写到磁盘上。提供缓冲区的原因是:

    为了缓和CPU与磁盘设备之间速度不匹配矛盾。文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。

    //创建文件缓冲区
    r := bufio.NewReader(fp)
    
    • 1
    • 2

    3. 循环读取文件中的内容,直到文件末尾位置。

    for {
        //遇到'\n'结束读取,但是'\n'也读取进入
        buf,err := r.ReadBytes('\n')
        fmt.Println("buf = ",string(buf))
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Println("err=",err)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在使用ReadBytes()函数时,传递的参数是\n,表示遇到\n就结束,所以使用了死循环(每循环一次,读取一行数据),只有到文件末尾了,才退出整个循环。最后,将读取的数据打印出来,注意ReadBytes()返回的是字节切片,所以在打印时要转换成字符串。

    4. 最后关闭文件

    //关闭文件
    defer fp.Close()
    
    • 1
    • 2

    现在我们已经完成了文件的创建,读取,以及将数据保存到文件的操作,在对文件操作时,我们需要指定文件的路径

    关于路径,有两种情况:

    • 第一:相对路径,所谓相对路径指的是文件相对于应用程序的路径。例如:上面我们一只使用的a.txt,这个文件,该文件存放的位置与可执行文件存储的路径是一样的。
    • 第二:绝对路径:指的是通过给定的这个路径直接能在我的电脑中找到这个文件。例如:D:\Info.txt,

    建议我们以后在开发中使用相对路径

    文件操作案例

    文件拷贝,将已有的文件复制一份,同时重新命名。

    基本的思路:

    1. 让用户输入要拷贝的文件的名称(源文件)以及目的文件的名称
    2. 创建目的文件
    3. 打开源文件,并且读取该文件中的内容
    4. 将从源文件中读取的内容写到目的文件中。
    var srcFileName string
    var dstFileName string
    fmt.Printf("请输入源文件名称:")
    fmt.Scan(&srcFileName)
    fmt.Println("请输入目的文件名称:")
    fmt.Scan(&dstFileName)
    if srcFileName == dstFileName {
        fmt.Println("源文件和目的文件名字不能相同")
        return
    }
    //只读方式打开源文件
    sF,err1 := os.Open(srcFileName)
    if err1 != nil {
        fmt.Println("err1=",err1)
        return
    }
    //新建目的文件
    dF,err2 := os.Create(dstFileName)
    if err2 != nil{
        fmt.Println("err2=",err2)
        return
    }
    //操作完毕,需要关闭文件
    defer sF.Close()
    defer dF.Close()
    //核心处理,从源文件读取内容,往目的文件写,读多少写多少
    buf := make([]byte,4*1024)//4k大小临时缓冲区
    for{
        n,err := sF.Read(buf)//从源文件读取内容,每次读取一部分
        if err != nil{
            fmt.Println("err=",err)
            if err == io.EOF{//文件读取完毕
                break
            }
        }
        //往目的文件写,读多少写多少
        dF.Write(buf[:n])
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
  • 相关阅读:
    [数据可视化] 漏斗图(Funnel Chart)
    React 学习-5
    第二次上机作业 大连理工大学
    Build U-Boot(基于TI AM64)
    10个Golang 数据库最佳实践
    Android的handler消息收发处理——子线程与主线程(UI线程)间的通信
    SpringBoot-将Bean放入容器的五种方式
    clickhouse-cpp接口函数
    基于JavaWeb+SSM+Vue“鼻护灵”微信小程序系统的设计和实现
    【场景化解决方案】销帮帮酷应用,帮助企业销售团队实现精细化管理
  • 原文地址:https://blog.csdn.net/weixin_47906106/article/details/132908438