Go 文件操作

2023-09-15 18:59:56

创建文件

将数据存储到文件之前,先要创建文件。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()
}

执行以上代码后,可以在程序文件存放的目录中,看到有一个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()

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

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

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

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

除了使用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()

在这里要注意的是,使用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()

以上程序中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()

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()
}

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
}

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

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

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

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)
    }
}

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

4. 最后关闭文件

//关闭文件
defer fp.Close()

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

关于路径,有两种情况:

  • 第一:相对路径,所谓相对路径指的是文件相对于应用程序的路径。例如:上面我们一只使用的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])
}
更多推荐

UI设计和平面设计的区别是什么?看完这篇一次搞懂

很多想要从事视觉领域工作的新手设计师,搞不懂UI设计和平面设计的区别;也有很多平面设计师工作后想转UI,却不知道该如何进行,导致择业和职业发展受阻,其实核心问题还是因为没有弄清楚UI设计和平面设计的区别是什么。这里先说明,UI设计和平面设计,是两个完全不同的设计领域。UI设计师着重于解决产品的用户习惯和易用体验,而平面

07JVM_内存模型和CAS与原子类

一、内存模型1.java内存模型Java内存结构是JMM(JavaMemoryModel)的意思。JMM定义了一套在多线程读写共享数据(成员变量,数组)时,对数据的原子性,见性,有序性的规则和保障。1.1原子性什么是原子性?原子性是指一个操作是不可中断的,即使多个线程一起执行,一个线程一旦开始,就不会被其他线程干扰。如

Django系列:Django开发环境配置与第一个Django项目

Django系列Django开发环境配置与第一个Django项目作者:李俊才(jcLee95):https://blog.csdn.net/qq_28550263邮箱:291148484@163.com本文地址:https://blog.csdn.net/qq_28550263/article/details/1328

自动化测试—选择器

根据id选择名字:<inputtype="text"id='searchtext'/>element=wd.find_element(By.CSS_SELECTOR,'#searchtext')element.send_keys('你好')根据class选择元素的两种方式:1.By.CLASS_NAME:element

form组件的封装(element ui ) 简单版本

当你使用Vue.js构建Web应用时,封装可复用组件是提高开发效率和代码可维护性的关键之一。在这篇文章中,我们将探讨如何使用Vue.js来创建一个通用的表单组件,以及如何将它封装成一个可配置的组件。实现思路拿下表单模板一个个的改造(文本,下拉,单选,复选等)按钮默认值的设定rules规则的处理创建通用的form组件这段

Arm机密计算架构技术(Armv9 CCA) 白皮书

1.概述在本篇文章中,我们将介绍机密计算(ConfidentialComputing)在现代计算平台中扮演的角色,并解释机密计算的原理。然后我们将说明Arm机密计算架构(ArmCCA)如何在Arm计算平台中实现机密计算。看完本文后,您将能够:定义机密计算描述复杂的系统信任链了解Realm(机密领域)是由ArmCCA引入

网络安全进阶学习第十八课——业务逻辑漏洞(附录:不同行业业务逻辑的漏洞)

文章目录一、互联网行业二、P2P金融行业三、电商行业四、政务行业总结一、互联网行业通用业务模块业务逻辑漏洞登录暴力破解用户名密码撞库验证码爆破和绕过、手机号撞库、账户权限绕过注册恶意用户批量注册、恶意验证注册账户、存储型XSS密码找回重置任意用户账户密码、批量重置用户密码、新密码劫持、短信验证码劫持、用户邮箱劫持篡改后

leetcode 1921. 消灭怪物的最大数量(每日一题)

最近学习的状态找回很多。慢慢来吧,加油!1921.消灭怪物的最大数量你正在玩一款电子游戏,在游戏中你需要保护城市免受怪物侵袭。给你一个下标从0开始且长度为n的整数数组dist,其中dist[i]是第i个怪物与城市的初始距离(单位:米)。怪物以恒定的速度走向城市。给你一个长度为n的整数数组speed表示每个怪物的速度,其

2023年中国研究生数学建模竞赛D题解题思路

为了更好的帮助大家第一天选题,这里首先为大家带来D题解题思路,分析对应赛题之后做题阶段可能会遇到的各种难点。稍后会带来D题的详细解析思路,以及相关的其他版本解题思路成品论文等资料。赛题难度评估:A、B>C>E、F>D选题人数评估:D>E、F>C>A、BD题区域双碳目标与路径规划研究以当下热门话题双碳碳中和为命题背景设置

孙哥Spring源码第24集

第24集处理AOP【视频来源于:B站up主孙帅sunsSpring源码视频】【微信号:suns45】1、谈一下你对ApplicationContext的理解BeanFactoryPostProcessorsBeanPostProcessor1.BDBeanFactoryPostProcessors、BeanPostPr

专利申请流程详解

专利申请的流程1、实用新型专利:是指对产品的形状、构造或者其结合所提出的适于实用的新的技术方案,指对有具体产品结构提出的改进或创造。与发明相比,实用新型专利申请对于技术的要求更低一点,在审查的时候不会进行详细的检索和对比,授权时间快,但实用新型的保护力度与发明专利的保护力度是不一样的。所需材料:请求书、说明书、权利要求

热文推荐