当前位置: 首页 > news >正文

【Go】Go文件操作详解

1. 前言

相信如果看过之前文章的朋友们一定知道我想讲什么了?灵魂三问:文件是什么?为什么需要文件?文件怎么操作?前面章节我们已经能够编写各种各样的功能代码了,但是一个很现实的问题就是我们没有任何 持久化存储 的能力!也就是说我们之前编写的任何代码中的数据都保存在内存中(内存具有掉电易失性),举一个例子:我们想开发一款魔塔游戏,要求拥有存档和读档的能力!我们就可以使用文件的读写操作来实现持久化功能

2. 编码小历史

由于文件操作涉及到编码规则以及字符集的影响,因此我将先介绍有关编码的历史发展脉络,编码集的发展阶段大致可以总结如下:ASCII -> GBK -> Unicode -> UTF-8

  • ASCII编码

众所周知,计算机起源于美国,对于老美来说只有26个英文字母,算上各种特殊符号也绝不会超过128个,因此表示一个字符使用7个比特位即可(2^7 = 128)因此使用1个字节来存储一个字符是绰绰有余的,因此诞生了赫赫有名的 “ASCII” 编码字符集

  • GBK编码

但是当计算机发展到东亚国家以后就不同了,中文、韩文、日文的字符也想在计算机中显示怎么办?哪怕是常见的中文也有几千个(1个字节肯定是存不下了)因此引入了扩展的中文字符集——GBK编码,使用2个字节表示一个字符,同时还必须保证兼容ASCII编码集。两个字节足以表示65536个字符,应对当前场景应该是没问题了

  • Unicode编码

随着计算机不断在世界范围内普及,每个国家都进行扩展,造成的后果就是很难统一管理维护。于是ISO国际化标准组织收集了世界范围内的字符,编写了"万国码"——Unicode编码,该种编码方式对于任何一个字符都使用两个字节进行存储:表示范围为65536个字符

  • UTF-8编码

虽然Unicode编码已经可以达到统一的效果了,但是老美不乐意了:原本只需要使用一个字节表示的a、b、c现在全部需要扩大两倍存储空间,这不闹吗???最后诞生了"UTF-8"字符集(可以与unicode相互转化),最终的效果就是对于ASCII码表字符使用1个字节存储,对于中文统一使用3个字节存储,其余文字字符各有对应规则

3. Go的字符和字节

在我看来字符就是字节比特流(一串二进制数),两者是等价的:比如 ‘a’ <=> 97,在对应的UTF-8规则集下两者具有对应关系,在Go语言当中字符类型可以有如下两种声明方式:

  1. 语法格式:var ch byte 或者 var ch uint8表示该字符占用1个字节
  2. 语法格式:var ch rune 或者 var ch int32表示该字符占用4个字节

使用1个字节表示字符:

func main() {// 声明方式1var ch1 bytech1 = 'a'fmt.Println(ch1)var ch2 uint8ch2 = 'b'fmt.Println(ch2)
}

使用4个字节表示字符:

func main() {// 声明方式2var ch3 runech3 = '米'fmt.Println(ch3)var ch4 int32ch4 = '饭'fmt.Println(ch4)
}

💡 注意:在Go语言源码层面byte类型与uint8类型是一样的,rune类型与int32类型是一样的(如果追踪源码会发现如下语句:type byte = uint8; type rune = int32)

4. 字符串

4.1 字符串存储原理

Go语言当中的string数据类型占用16个字节,其中前8个字节是一个指针,存储底层字节数组的起始地址;后8个字节是一个整数,存储字符串的长度(以字节为单位)

画板

string对应数据结构实现可以在源码包src/runtime/string.go中看到:

  • str:指向底层字节数组的地址
  • len:底层字节数组长度,可通过len内置函数获取

4.2 字符串的遍历

字符串遍历有如下两种方式:

  1. 使用len函数按照长度进行遍历
func main() {// 字符串遍历方式1:按照len遍历var str = "米饭666"for i := 0; i < len(str); i++ {fmt.Printf("%d, %c\n", str[i], str[i])}
}

代码运行结果:

  1. 使用range迭代遍历
func main() {// 字符串遍历方式2:按照range遍历for _, v := range str {fmt.Printf("%d, %c\n", v, v)}
}

代码运行结果:

💡 总结:Go语言当中的字符串使用len遍历时,获取的是每一个字节的内容(若包含中文则会出现乱码结果);当使用range进行遍历时,内部会帮助解析成unicode字符

4.3 字符串和字节串的转化

由于字符串的底层是一个字节数组,因此字符串和字节串存在相互转化的关系:

  • 字符串转字节串:字节数组 = []byte(字符串)
func main() {// 字符串转字节串var str = "米饭666"var byteArr = []byte(str)fmt.Println(byteArr)
}

代码运行结果:

  • 字节串转字符串:字符串 = string(字节数组)
func main() {// 字节串转字符串var byteArr = []byte{231, 177, 179, 233, 165, 173, 54, 54, 54}var str = string(byteArr)fmt.Println(str)
}

代码运行结果:

5. 读写文件

5.1 读文件

首先我们在当前main.go同级创建文件file.txt内容如下:

我们可以通过file, err := os.Open(file_path)打开一个文件,如果打开成功则返回对应的文件句柄

5.1.1 方式1:使用Read方法

语法格式:n, err := file.Read(空字节切片)

  • 如果读取失败则会将错误内容写入err中
  • 如果读取成功那么n就是读取的字节数,读取内容会存放到空字节切片中
func main() {// 打开文件file, err := os.Open("./file.txt")if err != nil {fmt.Println("打开文件失败, err:", err)}// 关闭文件句柄defer file.Close()var data = make([]byte, 1024)n, err := file.Read(data)if err != nil {fmt.Println("读取文件失败. err:", err)}fmt.Printf("读取到的字节数为:%d\n", n)fmt.Printf("读取内容为:%s\n", string(data[:n]))
}

代码运行结果:

5.1.2 方式2:使用ReadString方法

上述方式是按照字节进行读取的,我们可以使用内置包bufio.NewReader().ReadString按照指定分隔符进行读取(比如换行符\n读取一行)

func main() {// 打开文件file, err := os.Open("./file.txt")if err != nil {fmt.Println("打开文件失败!", err)}defer file.Close()// 读取文件reader := bufio.NewReader(file)for true {line, err := reader.ReadString('\n')if err == io.EOF {// 读取到结束fmt.Print(line)break}fmt.Print(line)}
}

代码运行结果:

5.1.3 方式3:使用ReadFile方法

我们可以使用ioutil.ReadFile(file_path)方法直接读取整个文件内容,适用于小型文件

func main() {// 读取文件content, err := ioutil.ReadFile("./file.txt")if err != nil {fmt.Println("读取文件失败!", err)}fmt.Println(string(content))
}

代码运行结果:

5.2 写文件

我们可以通过file, err := os.OpenFile(file_path, flag, fileMode)更一般性的打开一个文件

  • file_path:文件所在路径
  • flag:打开方式标记,比如os.O_CREATE:文件不存在则新建,os.O_REONLY:只读模式,os.O_APPEND:追加写入模式
  • fileMode:文件权限:例如0777表示 rwxrwxrwx
5.2.1 方式1:使用Write方法
func main() {// 一般性的打开文件file, err := os.OpenFile("./file.txt", os.O_CREATE|os.O_WRONLY, 0666)if err != nil {fmt.Println("打开文件失败!", err)}defer file.Close()// Write写入字节数组file.Write([]byte("Hello World\nHello ricejson\n"))
}
5.2.2 方式2:使用WriteString方法
func main() {// 一般性的打开文件file, err := os.OpenFile("./file.txt", os.O_CREATE|os.O_WRONLY, 0666)if err != nil {fmt.Println("打开文件失败!", err)}defer file.Close()// WriteString写入字符串writer := bufio.NewWriter(file)writer.WriteString("Hello world\n Hello ricejson\n")// 强制刷新缓冲区writer.Flush()
}
5.2.3 方式3:使用WriteFile方法
func main() {// WriteFile直接写文件ioutil.WriteFile("file.txt", []byte("Hello World\n"), 0666)
}

相关文章:

【Go】Go文件操作详解

1. 前言 相信如果看过之前文章的朋友们一定知道我想讲什么了&#xff1f;灵魂三问&#xff1a;文件是什么&#xff1f;为什么需要文件&#xff1f;文件怎么操作&#xff1f;前面章节我们已经能够编写各种各样的功能代码了&#xff0c;但是一个很现实的问题就是我们没有任何 持…...

[react+ts] useRef获取自定义组件dom或方法声明

想用useRef获取自定义组件? 如果获取dom,直接写 const sonRef useRef<HTMLDivElement>(null); 然后子组件用forwardRef包一层,注意是HTMLDivElement,别写错, 写HTMLElement不行 const Son forwardRef<HTMLDivElement, IProps>((props, ref) > {}) 切记这…...

AI 将在今年获得“永久记忆”,2028美国会耗尽能源储备

AI的“永久记忆”时代即将来临 谷歌前CEO施密特揭示了AI技术的前景&#xff0c;他相信即将在2025年迎来一场伟大的变化。AI将实现“永久记忆”&#xff0c;改变我们与科技的互动过程。施密特将现有的AI上下文窗口比作人类的短期记忆&#xff0c;难以持久保存信息。他的设想是…...

【视频笔记】基于PyTorch从零构建多模态(视觉)大模型 by Umar Jamil【持续更新】

视频链接: 基于PyTorch从零构建多模态(视觉)大模型 by Umar Jamil 从头编写一个视觉语言模型:PloyGamma,是谷歌的一个模型 1:原始图像 2:视觉编码器(本文是viT),通过对比学习进行训练。这个对比学习最开始是CLIP,后来被谷歌改成了SigLIP 3:线性投影层 4:如何将图…...

解决 C++ 中头文件相互引用和解耦问题

在 C 中&#xff0c;当多个 .h 文件相互引用时&#xff0c;可能会导致 循环依赖 或 头文件冗余 问题&#xff0c;进而引发编译时间延迟、代码复杂度增加等问题。为了有效地解耦和组织代码&#xff0c;可以采用以下几种策略和思想&#xff1a; 1. 前向声明&#xff08;Forward …...

河马剧场(短剧)APP的邀请码怎么填写

上篇给大家说到河马剧场免费看短剧还能领5.2元3天vip会员&#xff0c;本文就说一下河马剧场河马短剧APP的邀请码怎么填写。 河马短剧APP填写邀请码分三步&#xff1a; 1、安装登陆河马短剧APP 2、点击底部导航栏中间的“福利” 3、往下划会看到“填写邀请码领3天vip” 4、…...

01:C语言的本质

C语言的本质 1、ARM架构与汇编2、局部变量初始化与空间分配2.1、局部变量的初始化2.1、局部变量数组初始化 3、全局变量/静态变量初始化化与空间分配4、堆空间 1、ARM架构与汇编 ARM简要架构如下&#xff1a;CPU&#xff0c;ARM(能读能写)&#xff0c;Flash&#xff08;能读&a…...

第1章:数据库基础

第1章&#xff1a;数据库基础 1.1 数据库概述 1.1.1 什么是数据库 数据库的定义数据库的发展历程数据库的重要性 1.1.2 关系型数据库简介 关系型数据库模型常见的关系型数据库关系型数据库的特点 1.1.3 MySQL在企业中的应用 Web应用电商平台金融系统大数据存储 1.2 数据…...

C++教程 | string类的定义和初始化方法

在C中&#xff0c;string是标准库中用于处理字符串的类&#xff0c;定义在 头文件中&#xff0c;它提供了方便、灵活的字符串操作功能。以下是一些常见的定义和初始化string对象的方法&#xff1a; 1. 默认初始化 可以直接定义一个空的string对象&#xff0c;语法如下&#x…...

React中的合成事件

合成事件与原生事件 区别&#xff1a; 1. 命名不一样&#xff0c;原生用纯小写方式&#xff0c;react用小驼峰的方式 原生&#xff1a;onclick React的&#xff1a;onClick 2. 事件处理函数的写法不一样 原生的是传入一个字符串&#xff0c;react写法传入一个回调函数 3.…...

[SMARTFORMS] 创建FORM

输入事务码SMARTFORMS进入表单开发界面&#xff0c;选中表单&#xff0c;自定义表单名称ZFS_DEMO_2025 点击"创建"按钮&#xff0c;跳转至"SAP表格设计器"页面 在"表格属性"填写表单描述、指定页格式和样式 在"表格接口"可以填写SMART…...

成都和力九垠科技有限公司九垠赢系统Common存在任意文件上传漏洞

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...

基于Python的考研学习系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

『SQLite』几种向表中插入数据的方法

向表中插入数据 INSERT INTO 语句用来给数据库中的某个表中新增数据行。 案例 直接根据基本语法插入数据插入时不用全部指定列名方式根据查询结果将数据插入另一张表中 注意 上述内容详讲见文章&#xff1a;SQLite的INSERT操作&#xff08;内含案例&#xff09;...

什么是Kafka的重平衡机制?

Kafka 的重平衛机制是指在消费者组中新增或删除消费者时&#xff0c;Kafka 集群会重新分配主题分区给各个消费者&#xff0c;以保证每个消费者消费的分区数量尽可能均衡。 重平衡机制的目的是实现消费者的负载均衡和高可用性&#xff0c;以确保每个消费者都能够按照预期的方式…...

pdf预览 报:Failed to load module script

pdf 预览报&#xff1a; Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “application/octet-stream”. Strict MIME type checking is enforced for module scripts per HTML spec. 报错原因&#xff1a…...

AI 角色扮演法的深度剖析与实践

&#x1f4e2;&#x1f4e2;&#x1f4e2; 大家好&#xff0c;我是云楼Yunlord&#xff0c;CSDN博客之星人工智能领域前三名&#xff0c;多年人工智能学习工作经验&#xff0c;一位兴趣稀奇古怪的【人工智能领域博主】&#xff01;&#xff01;&#xff01;&#x1f61c;&#…...

weblogic问题

安装weblogic单机后启动weblogic进程&#xff1a; 第一行&#xff1a; 这是一个 su 命令&#xff0c;用于切换到 weblogic 用户。 第二行&#xff1a; 这是 weblogic 用户的 bash shell 会话。 第三行&#xff1a; 这是启动 WebLogic 服务器的脚本。 第四行&#xff1a; 这是 …...

Qt仿音乐播放器:客户端唯一化

一、铺垫 1.我们采用共享内存来进行客户端的唯一化&#xff1b; 2.我刚看到的时候&#xff0c;就感觉&#xff0c;这是人想出来的吗&#xff1f;太绝了 二、实例 int main(int argc, char *argv[]) {QApplication a(argc, argv);QSharedMemory shareMemory("Widget&qu…...

ceph文件系统

ceph文件系统&#xff1a;高度可扩展&#xff0c;分布式的存储文件系统&#xff0c;旨在提高性能&#xff0c;高可靠性和高可用的对 象存储&#xff0c;块存储&#xff0c;文件系统的存储。使用分布式的算法保证数据的高可用和一致性。 ceph的组件 1、MON&#xff1a;ceph m…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...