第11篇 文件操作——数据的持久化存储 仓颉原生中文编程
摘要 本文介绍了文件操作在编程中的重要性,展示了如何使用华为仓颉编程语言实现数据的持久化存储。主要内容包括: 文件操作的必要性:解释为何需要将数据保存到硬盘(如日记、游戏存档等场景) 基础操作示例: 文件写入(创建/覆盖文件) 文件读取 追加写入 常用数据格式处理: CSV格式(适合表格数据) JSON格式(适合结构化配置) 语法特点:特别说明仓颉语言的"类型后置"设计风格,并
第11篇 文件操作——数据的持久化存储
**作者:**中文编程倡导者—— 李金雨
联系方式: wbtm2718@qq.com
**目标读者:**编程入门(零基础)
核心理念: 使用华为仓颉原生中文编程,体验真正的国产编程语言
一、为什么需要文件操作?
想象一下:
- 你写了一篇作文,如果不保存,关机后就没了
- 你玩游戏的进度,如果不存档,下次就要从头开始
- 你通讯录里的联系人,如果不保存,手机重启就全丢了
文件操作就是让我们把数据保存到硬盘上,这样即使程序关闭、电脑关机,数据也不会丢失。这叫做持久化存储。
二、生活中的文件操作
例子1:写日记
- 打开日记本 → 打开文件
- 写下今天的事 → 写入数据
- 合上日记本 → 关闭文件
- 以后翻看 → 读取文件
例子2:图书馆借书系统
- 读取借阅记录文件 → 查看谁借了哪些书
- 写入新的借阅记录 → 记录新书被借走
- 修改归还日期 → 更新文件内容
三、仓颉语言中的文件操作
1. 写入文件
import std.fs.*
import std.io.*
main() {
// 要写入的内容
var 日记内容 = """今天是2024年1月15日,星期一。
今天学习了仓颉编程语言,感觉很有趣!
虽然类型后置的语法有点不习惯,但总体还是挺好懂的。
"""
try {
// 打开文件(如果不存在则创建)
var 文件 = File.open("我的日记.txt", "w")
// 写入内容
文件.write(日记内容)
// 关闭文件
文件.close()
println("日记保存成功!")
} catch (异常: Exception) {
println("保存失败:${异常.message}")
}
}
2. 读取文件
import std.fs.*
import std.io.*
main() {
try {
// 以只读方式打开文件
var 文件 = File.open("我的日记.txt", "r")
// 读取所有内容
var 内容 = 文件.readAll()
// 关闭文件
文件.close()
// 显示内容
println("=== 日记内容 ===")
println(内容)
} catch (异常: Exception) {
println("读取失败:${异常.message}")
}
}
3. 追加写入
import std.fs.*
main() {
try {
// 以追加模式打开文件("a"表示append)
var 文件 = File.open("我的日记.txt", "a")
// 追加新内容
文件.write("\n\n--- 补充 ---\n")
文件.write("今天还学会了文件操作,可以保存数据了!")
文件.close()
println("追加内容成功!")
} catch (异常: Exception) {
println("追加失败:${异常.message}")
}
}
四、CSV文件操作
CSV(Comma Separated Values,逗号分隔值)是一种简单的表格数据格式,可以用Excel打开。
写入学生成绩表
import std.fs.*
import std.collection.*
class 学生成绩 {
var 姓名: String
var 语文: Int64
var 数学: Int64
var 英语: Int64
init(姓名: String, 语文: Int64, 数学: Int64, 英语: Int64) {
this.姓名 = 姓名
this.语文 = 语文
this.数学 = 数学
this.英语 = 英语
}
func 转为CSV行(): String {
return "${姓名},${语文},${数学},${英语}"
}
}
main() {
var 学生列表 = ArrayList<学生成绩>()
学生列表.add(学生成绩("张三", 85, 92, 78))
学生列表.add(学生成绩("李四", 90, 88, 95))
学生列表.add(学生成绩("王五", 78, 85, 88))
try {
var 文件 = File.open("学生成绩表.csv", "w")
// 写入表头
文件.write("姓名,语文,数学,英语\n")
// 写入数据
for (学生 in 学生列表) {
文件.write(学生.转为CSV行() + "\n")
}
文件.close()
println("成绩表保存成功!")
} catch (异常: Exception) {
println("保存失败:${异常.message}")
}
}
生成的CSV文件内容:
姓名,语文,数学,英语
张三,85,92,78
李四,90,88,95
王五,78,85,88
读取CSV文件
import std.fs.*
import std.collection.*
import std.convert.*
main() {
try {
var 文件 = File.open("学生成绩表.csv", "r")
var 所有行 = 文件.readAll().split("\n")
文件.close()
println("=== 学生成绩表 ===")
println("姓名\t语文\t数学\t英语\t总分")
println("----------------------------------------")
// 跳过表头,从第1行开始读取
for (i in 1..所有行.size) {
var 行 = 所有行[i]
if (行.isEmpty()) {
continue
}
var 字段 = 行.split(",")
var 姓名 = 字段[0]
var 语文 = Int64.parse(字段[1])
var 数学 = Int64.parse(字段[2])
var 英语 = Int64.parse(字段[3])
var 总分 = 语文 + 数学 + 英语
println("${姓名}\t${语文}\t${数学}\t${英语}\t${总分}")
}
} catch (异常: Exception) {
println("读取失败:${异常.message}")
}
}
五、JSON文件操作
JSON(JavaScript Object Notation)是一种更现代的数据格式,结构清晰,易于阅读。
保存配置信息
import std.fs.*
class 程序配置 {
var 程序名称: String = "学生管理系统"
var 版本: String = "1.0"
var 作者: String = "小明"
var 最大学生数: Int64 = 100
var 自动保存: Bool = true
func 转为JSON(): String {
return """{
"程序名称": "${程序名称}",
"版本": "${版本}",
"作者": "${作者}",
"最大学生数": ${最大学生数},
"自动保存": ${自动保存}
}"""
}
}
main() {
var 配置 = 程序配置()
try {
var 文件 = File.open("配置.json", "w")
文件.write(配置.转为JSON())
文件.close()
println("配置保存成功!")
} catch (异常: Exception) {
println("保存失败:${异常.message}")
}
}
生成的JSON文件:
{
"程序名称": "学生管理系统",
"版本": "1.0",
"作者": "小明",
"最大学生数": 100,
"自动保存": true
}
六、语法设计讨论:文件操作中的类型声明
同学们,在学习文件操作时,我们再次遇到了仓颉的类型后置语法问题。
看看文件操作的代码:
class 学生成绩 {
var 姓名: String // 类型后置
var 语文: Int64 // 类型后置
var 数学: Int64 // 类型后置
var 英语: Int64 // 类型后置
init(姓名: String, 语文: Int64, 数学: Int64, 英语: Int64) { // 参数类型后置
// ...
}
func 转为CSV行(): String { // 返回值类型后置
// ...
}
}
main() {
var 学生列表: ArrayList<学生成绩> // 泛型类型后置
// ...
}
按照中国人的语言习惯:
- 我们习惯说"字符串类型的姓名"、“整数类型的语文成绩”
- 我们习惯说"学生成绩列表类型的变量"
但仓颉的写法:
var 姓名: String→ 读作"姓名,字符串类型的"(定语后置)ArrayList<学生成绩>→ 读作"学生成绩类型的列表"(泛型也是后置)
如果仓颉能改进成C#风格:
// 假设的改进语法
class 学生成绩 {
String 姓名 // "字符串类型的姓名"
Int64 语文 // "整数类型的语文成绩"
Int64 数学
Int64 英语
init(String 姓名, Int64 语文, Int64 数学, Int64 英语) {
// ...
}
String 转为CSV行() { // "字符串类型的转为CSV行方法"
// ...
}
}
main() {
ArrayList<学生成绩> 学生列表 // "学生成绩列表类型的学生列表"
// ...
}
这样读起来多么自然:“定义一个学生成绩类,它有字符串类型的姓名属性,整数类型的语文、数学、英语成绩属性…”
华为在设计仓颉语言时,采用了类似Rust的类型后置语法,这就像是在说"姓名 字符串类型的"而不是"字符串类型的姓名"。现代汉语都是定语前置的,我们希望中文编程语言能真正符合中国人的语言习惯!
七、文件路径操作
import std.fs.*
import std.path.*
main() {
// 获取当前工作目录
var 当前目录 = Path.current()
println("当前目录:${当前目录}")
// 拼接路径
var 文件路径 = Path.join(当前目录, "数据", "学生.txt")
println("文件路径:${文件路径}")
// 检查文件是否存在
if (File.exists("我的日记.txt")) {
println("文件存在")
} else {
println("文件不存在")
}
// 创建目录
try {
Dir.create("备份数据")
println("目录创建成功")
} catch (异常: Exception) {
println("创建目录失败:${异常.message}")
}
}
八、练习时间
练习1:日记本程序
创建一个简单的日记本程序:
- 可以输入当天的日记内容
- 将日记保存到以日期命名的文件中(如"2024-01-15.txt")
- 可以按日期读取以前的日记
练习2:通讯录管理
创建一个通讯录程序:
- 可以添加联系人(姓名、电话、邮箱)
- 可以删除联系人
- 可以查找联系人
- 所有数据保存到CSV文件中
练习3:记账本
创建一个记账本程序:
- 记录每笔收入和支出(日期、类型、金额、备注)
- 可以查看某个月的总收入和总支出
- 数据保存到JSON文件中
九、本课小结
今天我们学习了:
- 文件操作的重要性:实现数据的持久化存储
- 写入文件:创建新文件或覆盖已有文件
- 读取文件:从文件中获取数据
- 追加写入:在文件末尾添加内容
- CSV格式:简单的表格数据格式
- JSON格式:结构化的数据格式
- 文件路径操作:处理文件和目录的路径
类型语法思考:在文件操作中,我们频繁地声明类属性、方法参数、返回值类型,每一次都要面对类型后置的语法。希望未来的中文编程语言能让类型声明更符合中国人的说话习惯,真正做到"说人话"!
十、课后作业
-
完善"学生管理系统"的文件存储功能:
- 将学生信息保存到JSON文件中
- 程序启动时自动读取学生信息
- 添加学生、删除学生后自动保存
-
创建一个"单词本"程序:
- 可以添加单词(英文、中文释义、例句)
- 可以按字母顺序查看所有单词
- 可以搜索单词
- 数据保存到CSV文件中
-
思考:在你的日常生活中,还有哪些数据需要持久化存储?如何用文件操作来实现?
下篇预告:第12篇《综合实战——制作一个学生管理系统》,综合运用前面学到的所有知识,完成一个完整的项目!
更多推荐

所有评论(0)