把数据保存成 CSV 文件并分享出去

« 返回首页

有用户问:App 里记了一堆数据(记账、打卡、测量值),想导出成一个 CSV 文件,再通过微信、QQ 或邮件发给别人,用电脑上的表格软件打开,怎么做?

能实现,不需要拓展。 用到三样现成的东西:

  • 列表抽屉的「列表转换为CSV表」:把「列表的列表」(每一项是一行)变成 CSV 文本,逗号、引号、换行这些特殊字符会自动加引号处理;
  • 文件管理器的保存文件:把文本写成文件;
  • 信息分享器的分享文件:弹出系统分享面板,用户自己选发到哪里。

思路:列表 → CSV 文本 → 存成文件 → 存好了再分享。最后这一步的「存好了再」是关键,下面实验三会讲为什么。

CSV 就是「逗号分隔的纯文本」,一行一条记录,同一行里的各项用逗号隔开。例如:

日期,项目,金额
2026-09-30,午饭,25
2026-09-30,地铁,4

WPS、Excel、Numbers、谷歌表格都能直接打开,一格一格排好。

准备

  1. 拖两个文本输入框:文本输入框_项目(提示「项目」)、文本输入框_金额(提示「金额」,勾选「仅限数字」)。
  2. 拖三个按钮:按钮_记一笔、按钮_导出、按钮_导入,再拖一个标签 标签1 显示状态。
  3. 拖四个非可视组件:微数据库、文件管理器、信息分享器(在「社交应用」里)、计时器。文件管理器和计时器的属性都不用改。

实验一:先把数据记下来

每记一笔就是一行:日期、项目、金额三项组成一个小列表,所有行放进一个大列表 账目,同时存进微数据库,退出 App 再进来数据还在。

global 账目 = []

when Screen1.Initialize() {
  账目 = 微数据库1.GetValue("账目", [])
  标签1.Text = join("已有 ", length(账目), " 笔")
}

when 按钮_记一笔.Click() {
  var 日期 = 计时器1.FormatDateTime(计时器1.Now(), "yyyy-MM-dd")
  listAdd(账目, [日期, 文本输入框_项目.Text, 文本输入框_金额.Text])
  微数据库1.StoreValue("账目", 账目)
  文本输入框_项目.Text = ""
  文本输入框_金额.Text = ""
  标签1.Text = join("已有 ", length(账目), " 笔")
}

跑起来看: 记三笔,标签依次变成「已有 1 笔」「已有 2 笔」「已有 3 笔」。在伴侣里点「重置连接」重新连上,标签仍然显示 3 笔,说明存住了。

实验二:导出成 CSV 文件

先拼出表头行,再把全部账目接在后面,交给「列表转换为CSV表」变成文本,最后保存:

global 账目 = []

when 按钮_导出.Click() {
  if (length(账目) == 0) {
    标签1.Text = "还没有数据可导出"
  } else {
    var 表格 = [["日期", "项目", "金额"]]
    listAppend(表格, 账目)
    文件管理器1.SaveFile(listToCsvTable(表格), "记账.csv")
  }
}

when 文件管理器1.AfterFileSaved(文件名) {
  标签1.Text = join("已保存:", 文件名)
}

跑起来看: 点「导出」,标签显示「已保存:记账.csv」。

几点说明:

  • 文件名只写名字,不要以 / 开头。这样文件落在应用自己的目录里(安卓是 Android/data/包名/files/,鸿蒙是应用沙箱),不需要任何存储权限。
  • 用 listAppend 把 账目 接到 表格 后面,而不是直接往 账目 里插表头:账目 是要长期保存的数据,不能被导出动作改掉。
  • 项目名里有逗号(比如「午饭,加蛋」)也没关系,「列表转换为CSV表」会自动给这一格加上引号,表格软件打开还是一格。自己用 join 拼逗号就会错位,这是推荐用内建积木的原因。

实验三:保存好之后再分享

把实验二的「文件存储完毕时」事件改成直接分享:

when 文件管理器1.AfterFileSaved(文件名) {
  标签1.Text = "正在打开分享面板…"
  信息分享器1.ShareFile(文件名)
}

跑起来看: 点「导出」,系统分享面板弹出来,选微信发给文件传输助手,电脑上打开就是一张三列的表格。

为什么不在按钮里 SaveFile 下一行直接 ShareFile?因为保存文件是异步的:SaveFile 只是把写文件的活交出去就立刻返回,这时文件可能还没写完,分享出去的是空文件或旧文件。「文件存储完毕时」事件触发时文件一定已经写好了,在这里分享最稳。

为什么只写 文件名 就能找到文件?文件管理器和信息分享器对「不以 / 开头的文件名」用的是同一个默认目录(屏幕的「默认文件范围」,默认值「应用」),两边说的是同一个文件。

实验四:文件名带上日期,附一句说明

每次导出都叫「记账.csv」,对方收到好几份分不清。文件名带上导出时间,分享时再附一句话:

global 账目 = []

when 按钮_导出.Click() {
  if (length(账目) == 0) {
    标签1.Text = "还没有数据可导出"
  } else {
    var 表格 = [["日期", "项目", "金额"]]
    listAppend(表格, 账目)
    var 名字 = join("记账_", 计时器1.FormatDateTime(计时器1.Now(), "yyyyMMdd_HHmm"), ".csv")
    文件管理器1.SaveFile(listToCsvTable(表格), 名字)
  }
}

when 文件管理器1.AfterFileSaved(文件名) {
  信息分享器1.ShareFileWithMessage(文件名, join("共 ", length(账目), " 笔账目,用 WPS 或 Excel 打开"))
}

跑起来看: 分享出去的文件名类似「记账_20260930_1830.csv」。发到微信时附言会作为单独一条消息,发邮件时会出现在正文里(具体取决于接收的 App)。

实验五:把 CSV 读回列表

导出只是一半,换了手机想把数据导回来也常用。用「读取文件」读出文本,「CSV表转换为列表」变回列表的列表,去掉第 1 行表头就是原来的账目:

global 账目 = []

when 按钮_导入.Click() {
  文件管理器1.ReadFrom("记账.csv")
}

when 文件管理器1.GotText(文本) {
  var 表格 = listFromCsvTable(文本)
  listRemove(表格, 1)
  账目 = 表格
  微数据库1.StoreValue("账目", 账目)
  标签1.Text = join("已导入 ", length(账目), " 笔")
}

跑起来看: 先用实验二的写法导出「记账.csv」,再清空数据(或换一台手机把文件拷进应用目录),点「导入」,标签显示导入的笔数,和导出前一致。

常见问题

现象 原因 解决
Excel 打开中文是乱码 文件是不带 BOM 的 UTF-8,老版本 Excel 双击打开时按本地编码猜 用 WPS、Numbers、新版 Excel 直接打开都正常;老版 Excel 用「数据 → 从文本/CSV」导入,编码选 UTF-8
分享出去的是空文件或旧内容 在 SaveFile 下一行直接分享,文件还没写完 放到「文件存储完毕时」事件里分享(实验三)
分享时提示找不到文件 保存时文件名以 / 开头,或者改过屏幕的「默认文件范围」、文件管理器的「范围」,两边目录不一致 文件名只写名字,两个范围都保持默认「应用」;或者直接把「文件存储完毕时」给的 文件名 原样传给分享
表格列错位 自己用 join 拼逗号,内容里本身带逗号或换行 用「列表转换为CSV表」,它会自动加引号
金额在表格里不能求和 输入框里带了空格或「元」字 输入框勾选「仅限数字」,或存之前用 trim 去掉空格
想每次追加而不是覆盖 SaveFile 会覆盖同名文件 用 AppendToFile 追加一行,写入内容用「列表转换为CSV行」再接一个换行;注意第一次要先写表头
分享面板里没有想要的 App 接收方 App 没有声明能收这种文件 换一个目标(微信、QQ、邮箱、网盘都能收 .csv),或把扩展名改成 .txt 试试

平台说明

  • 安卓:文件在 Android/data/包名/files/ 下,不需要存储权限;卸载 App 时会一起删除,要长期保存记得分享或导出出去。
  • 鸿蒙:文件管理器的「应用」范围就是应用沙箱,信息分享器按同一个目录解析文件名,本文所有积木原样可用。

相关文档

文档反馈