【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语言当中字符类型可以有如下两种声明方式:
- 语法格式:
var ch byte或者var ch uint8表示该字符占用1个字节 - 语法格式:
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 字符串的遍历
字符串遍历有如下两种方式:
- 使用
len函数按照长度进行遍历
func main() {// 字符串遍历方式1:按照len遍历var str = "米饭666"for i := 0; i < len(str); i++ {fmt.Printf("%d, %c\n", str[i], str[i])}
}
代码运行结果:

- 使用
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. 前言 相信如果看过之前文章的朋友们一定知道我想讲什么了?灵魂三问:文件是什么?为什么需要文件?文件怎么操作?前面章节我们已经能够编写各种各样的功能代码了,但是一个很现实的问题就是我们没有任何 持…...
[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技术的前景,他相信即将在2025年迎来一场伟大的变化。AI将实现“永久记忆”,改变我们与科技的互动过程。施密特将现有的AI上下文窗口比作人类的短期记忆,难以持久保存信息。他的设想是…...
【视频笔记】基于PyTorch从零构建多模态(视觉)大模型 by Umar Jamil【持续更新】
视频链接: 基于PyTorch从零构建多模态(视觉)大模型 by Umar Jamil 从头编写一个视觉语言模型:PloyGamma,是谷歌的一个模型 1:原始图像 2:视觉编码器(本文是viT),通过对比学习进行训练。这个对比学习最开始是CLIP,后来被谷歌改成了SigLIP 3:线性投影层 4:如何将图…...
解决 C++ 中头文件相互引用和解耦问题
在 C 中,当多个 .h 文件相互引用时,可能会导致 循环依赖 或 头文件冗余 问题,进而引发编译时间延迟、代码复杂度增加等问题。为了有效地解耦和组织代码,可以采用以下几种策略和思想: 1. 前向声明(Forward …...
河马剧场(短剧)APP的邀请码怎么填写
上篇给大家说到河马剧场免费看短剧还能领5.2元3天vip会员,本文就说一下河马剧场河马短剧APP的邀请码怎么填写。 河马短剧APP填写邀请码分三步: 1、安装登陆河马短剧APP 2、点击底部导航栏中间的“福利” 3、往下划会看到“填写邀请码领3天vip” 4、…...
01:C语言的本质
C语言的本质 1、ARM架构与汇编2、局部变量初始化与空间分配2.1、局部变量的初始化2.1、局部变量数组初始化 3、全局变量/静态变量初始化化与空间分配4、堆空间 1、ARM架构与汇编 ARM简要架构如下:CPU,ARM(能读能写),Flash(能读&a…...
第1章:数据库基础
第1章:数据库基础 1.1 数据库概述 1.1.1 什么是数据库 数据库的定义数据库的发展历程数据库的重要性 1.1.2 关系型数据库简介 关系型数据库模型常见的关系型数据库关系型数据库的特点 1.1.3 MySQL在企业中的应用 Web应用电商平台金融系统大数据存储 1.2 数据…...
C++教程 | string类的定义和初始化方法
在C中,string是标准库中用于处理字符串的类,定义在 头文件中,它提供了方便、灵活的字符串操作功能。以下是一些常见的定义和初始化string对象的方法: 1. 默认初始化 可以直接定义一个空的string对象,语法如下&#x…...
React中的合成事件
合成事件与原生事件 区别: 1. 命名不一样,原生用纯小写方式,react用小驼峰的方式 原生:onclick React的:onClick 2. 事件处理函数的写法不一样 原生的是传入一个字符串,react写法传入一个回调函数 3.…...
[SMARTFORMS] 创建FORM
输入事务码SMARTFORMS进入表单开发界面,选中表单,自定义表单名称ZFS_DEMO_2025 点击"创建"按钮,跳转至"SAP表格设计器"页面 在"表格属性"填写表单描述、指定页格式和样式 在"表格接口"可以填写SMART…...
成都和力九垠科技有限公司九垠赢系统Common存在任意文件上传漏洞
免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...
基于Python的考研学习系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
『SQLite』几种向表中插入数据的方法
向表中插入数据 INSERT INTO 语句用来给数据库中的某个表中新增数据行。 案例 直接根据基本语法插入数据插入时不用全部指定列名方式根据查询结果将数据插入另一张表中 注意 上述内容详讲见文章:SQLite的INSERT操作(内含案例)...
什么是Kafka的重平衡机制?
Kafka 的重平衛机制是指在消费者组中新增或删除消费者时,Kafka 集群会重新分配主题分区给各个消费者,以保证每个消费者消费的分区数量尽可能均衡。 重平衡机制的目的是实现消费者的负载均衡和高可用性,以确保每个消费者都能够按照预期的方式…...
pdf预览 报:Failed to load module script
pdf 预览报: 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. 报错原因:…...
AI 角色扮演法的深度剖析与实践
📢📢📢 大家好,我是云楼Yunlord,CSDN博客之星人工智能领域前三名,多年人工智能学习工作经验,一位兴趣稀奇古怪的【人工智能领域博主】!!!😜&#…...
weblogic问题
安装weblogic单机后启动weblogic进程: 第一行: 这是一个 su 命令,用于切换到 weblogic 用户。 第二行: 这是 weblogic 用户的 bash shell 会话。 第三行: 这是启动 WebLogic 服务器的脚本。 第四行: 这是 …...
Qt仿音乐播放器:客户端唯一化
一、铺垫 1.我们采用共享内存来进行客户端的唯一化; 2.我刚看到的时候,就感觉,这是人想出来的吗?太绝了 二、实例 int main(int argc, char *argv[]) {QApplication a(argc, argv);QSharedMemory shareMemory("Widget&qu…...
ceph文件系统
ceph文件系统:高度可扩展,分布式的存储文件系统,旨在提高性能,高可靠性和高可用的对 象存储,块存储,文件系统的存储。使用分布式的算法保证数据的高可用和一致性。 ceph的组件 1、MON:ceph m…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
