App Inventor 2 文件操作教程 - 创建/读取/写入/管理文件

« 返回首页

概述

App Inventor 2提供了 File 组件进行文件操作。本文介绍:

  • 文件路径概念
  • 创建文件和目录
  • 读取和写入文件
  • 文件管理(复制、删除)
  • FileTools扩展的高级功能

File组件核心方法

方法 说明
SaveFile(text, fileName) 保存文本到文件
AppendToFile(text, fileName) 追加文本到文件
ReadFrom(fileName) 读取文件内容
Delete(fileName) 删除文件

核心事件

事件 参数 说明
GotText(text) 文件内容 读取完成时触发
Saved(fileName) 文件名 保存完成时触发

文件路径

路径格式

App Inventor中的文件路径以 / 开头:

路径 说明
/fileName 应用私有目录(默认)
/sdcard/fileName 外部存储根目录
/sdcard/DCIM/ 相册目录
/sdcard/Download/ 下载目录
/sdcard/AppInventor/ App Inventor默认目录

创建指定文件路径

when 按钮_创建文件.Click() {
  var 文件路径 = "/sdcard/MyApp/data.txt"
  文件管理器1.SaveFile("初始内容", 文件路径)
}
when 文件管理器1.SaveFile(文件名) {
  标签_状态.Text = join("✅ 文件已创建:", 文件名)
}

注意:Android 10+的分区存储限制,应用默认只能访问自己的私有目录。访问 /sdcard/ 其他目录需要 WRITE_EXTERNAL_STORAGE 权限。

创建目录

App Inventor的File组件不能直接创建目录,但可以通过以下方式间接实现:

方法1:保存文件时自动创建路径

// 保存文件到子目录,目录会自动创建
文件管理器1.SaveFile("数据", "/sdcard/MyApp/subfolder/file.txt")

方法2:使用FileTools扩展

文件管理器_Tools1.MakeDirectory("/sdcard/MyApp/new_folder")

写入文件

写入文本

when 按钮_保存.Click() {
  var 内容 = 文本输入框_内容.Text
  文件管理器1.SaveFile(内容, "/sdcard/MyApp/notes.txt")
}

追加内容

when 按钮_追加.Click() {
  var 时间戳 = 计时器1.FormatDateTime(计时器1.Now(), "yyyy-MM-dd HH:mm:ss")
  var 追加内容 = join(时间戳, ": ", 文本输入框_内容.Text, "\n")
  文件管理器1.AppendToFile(追加内容, "/sdcard/MyApp/log.txt")
}

写入JSON数据

when 按钮_保存数据.Click() {
  global 数据字典 = create_dictionary("name", 文本输入框_姓名.Text, "score", 输入框_分数.Text, "date", Clock1.FormatDateTime(Clock1.Now(), "yyyy-MM-dd"))
  global JSON文本 = JsonTextEncode(数据字典)
  文件管理器1.SaveFile(JSON文本, "/sdcard/MyApp/data.json")
}

读取文件

基本读取

when 按钮_读取.Click() {
  文件管理器1.ReadFrom("/sdcard/MyApp/notes.txt")
}
when 文件管理器1.GotText(内容) {
  标签_内容.Text = 内容
}

读取并解析JSON

when 文件管理器1.GotText(内容) {
  global 数据 = JsonTextDecode(内容)
  global 姓名 = Dictionary.Get(数据, "name")
  global 分数 = Dictionary.Get(数据, "score")
  标签_显示.Text = join(姓名, ":", 分数, "分")
}

逐行处理

when 文件管理器1.GotText(内容) {
  var 行列表 = split(内容, "\n")
  var i = 1
  while i <= length(行列表) {
    var 当前行 = 行列表[i]
    // 处理每一行...
    var i = i + 1
  }
}

CSV文件操作

写入CSV

when 按钮_导出CSV.Click() {
  global CSV内容 = "姓名,年龄,城市\n"
  global i = 1
  while (i <= lengthOfList(数据列表)) {
    global 记录 = selectListItem(数据列表, i)
    global CSV内容 = join(CSV内容, Dictionary.Get(记录, "name"), ",", Dictionary.Get(记录, "age"), ",", Dictionary.Get(记录, "city"), "\n")
    global i = i + 1
  }
  文件管理器1.SaveFile(CSV内容, "/sdcard/MyApp/export.csv")
}

读取CSV

when 文件管理器1.GotText(内容) {
  global 行列表 = split(内容, "\n")
  global 数据列表 = []
  global i = 2  // 跳过标题行
  while (i <= lengthOfList(行列表)) {
    global 字段 = split(selectListItem(行列表, i), ",")
    if (lengthOfList(字段) >= 3) {
      global 记录 = create_dictionary("name", selectListItem(字段, 1), "age", selectListItem(字段, 2), "city", selectListItem(字段, 3))
      addItemsTo(数据列表, 记录)
    }
    global i = i + 1
  }
}

FileTools扩展

FileTools 扩展提供了更强大的文件操作能力。

核心功能

功能 方法
复制文件 CopyFile(source, dest)
移动文件 MoveFile(source, dest)
列出目录 ListFiles(directory)
创建目录 MakeDir(path)
删除目录 DeleteDir(path)
文件是否存在 Exists(path)
保存到相册 SaveFileToGallery(path)
扫描媒体文件 ScanFile(path)

使用示例

// 复制文件到相册
when 按钮_保存到相册.Click() {
  文件管理器_Tools1.CopyFile(图片路径, join("/sdcard/DCIM/Camera/photo_", 时间戳, ".png"))
  文件管理器_Tools1.扫描文件(join("/sdcard/DCIM/Camera/photo_", 时间戳, ".png"))
  // 列出目录文件
}
when 按钮_列出文件.Click() {
  文件管理器_Tools1.ListDirectory("/sdcard/MyApp/")
}
when 文件管理器_Tools1.ListFiles(文件列表) {
  var 显示 = ""
  var i = 1
  while i <= length(文件列表) {
    var 显示 = join(显示, 文件列表[i], "\n")
    var i = i + 1
  }
  var 标签_文件文本 = 显示
}

存储照片

从Camera保存到指定路径

when 按钮_拍照.Click() {
  照相机1.TakePicture()
}
when 照相机1.AfterPicture(图片路径) {
  // 复制到自己的目录
  var 新路径 = join("/sdcard/MyApp/photos/", 计时器1.FormatDateTime(计时器1.Now(), "yyyyMMdd_HHmmss"), ".jpg")
  文件管理器_Tools1.CopyFile(图片路径, 新路径)
  标签_状态.Text = join("✅ 照片已保存:", 新路径)
}

存储到相册(通知系统刷新)

when 按钮_存相册.Click() {
  文件管理器_Tools1.SaveFile(图片路径)
  // FileTools会自动通知系统扫描
}

已知问题:部分设备保存到相册后需要重启手机才可见。使用 ScanFile 方法可以触发系统媒体扫描。

常见问题

Q1: 保存文件时提示权限拒绝?

Android 6.0+需要动态申请存储权限。在Screen1的Properties中设置:

  • ReadWriteExternalStorage = true

Q2: 如何判断文件是否存在?

使用FileTools扩展的 Exists 方法,或者尝试读取文件:

文件管理器1.ReadFrom(目标路径)
when 文件管理器1.GotText(内容) {
  if 内容 == "" {
    标签_状态.Text = "文件不存在或为空"
  } else {
    标签_状态.Text = "文件存在"
  }
}

Q3: 如何处理大文件?

  • 读取大文件(>1MB)可能导致App卡顿
  • 使用分块读取或只读取需要的部分
  • 图片文件直接用Image组件加载路径,不需要用File读取

Q4: FileTools扩展保存到相册需要重启?

这是Android媒体扫描机制的已知问题。解决方案:

  1. 调用 ScanFile 主动触发扫描
  2. 使用 MediaStore API(需要扩展支持)
  3. 接受这个限制,告知用户稍等片刻

总结

需求 组件/方法 推荐
简单读写 File组件 ✅
复制/移动/目录 FileTools扩展 ✅
保存到相册 FileTools ✅
CSV导出 File + 文本处理 ✅
JSON数据 File + 字典 ✅
大文件处理 WebView + JS 高级
文档反馈