当前位置: 首页 > 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…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...