概述
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默认目录 |
创建指定文件路径
当 按钮_创建文件.被点击
设 文件路径 = "/sdcard/MyApp/data.txt"
调用 File1.保存文件("初始内容", 文件路径)
当 File1.保存完成(文件名)
标签_状态.文本 = "✅ 文件已创建:" & 文件名
注意:Android 10+的分区存储限制,应用默认只能访问自己的私有目录。访问
/sdcard/其他目录需要WRITE_EXTERNAL_STORAGE权限。
创建目录
App Inventor的File组件不能直接创建目录,但可以通过以下方式间接实现:
方法1:保存文件时自动创建路径
' 保存文件到子目录,目录会自动创建
调用 File1.保存文件("数据", "/sdcard/MyApp/subfolder/file.txt")
方法2:使用FileTools扩展
调用 FileTools1.创建目录("/sdcard/MyApp/new_folder")
写入文件
写入文本
当 按钮_保存.被点击
设 内容 = 输入框_内容.文本
调用 File1.保存文件(内容, "/sdcard/MyApp/notes.txt")
追加内容
当 按钮_追加.被点击
设 时间戳 = Clock1.格式化日期时间(Clock1.当前时间(), "yyyy-MM-dd HH:mm:ss")
设 追加内容 = 时间戳 & ": " & 输入框_内容.文本 & "\n"
调用 File1.追加文件(追加内容, "/sdcard/MyApp/log.txt")
写入JSON数据
当 按钮_保存数据.被点击
设 数据字典 = 创建字典(
"name" → 输入框_姓名.文本,
"score" → 输入框_分数.文本,
"date" → Clock1.格式化日期时间(Clock1.当前时间(), "yyyy-MM-dd")
)
设 JSON文本 = 调用 文本.转JSON(数据字典)
调用 File1.保存文件(JSON文本, "/sdcard/MyApp/data.json")
读取文件
基本读取
当 按钮_读取.被点击
调用 File1.读取文件("/sdcard/MyApp/notes.txt")
当 File1.收到文本(内容)
标签_内容.文本 = 内容
读取并解析JSON
当 File1.收到文本(内容)
设 数据 = 调用 文本.从JSON解析(内容)
设 姓名 = 从字典 数据 获取 "name"
设 分数 = 从字典 数据 获取 "score"
标签_显示.文本 = 姓名 & ":" & 分数 & "分"
逐行处理
当 File1.收到文本(内容)
设 行列表 = 分割文本(内容, "\n")
设 i = 1
当 i ≤ 列表长度(行列表)
设 当前行 = 列表第i项(行列表)
' 处理每一行...
设 i = i + 1
CSV文件操作
写入CSV
当 按钮_导出CSV.被点击
设 CSV内容 = "姓名,年龄,城市\n"
设 i = 1
当 i ≤ 列表长度(数据列表)
设 记录 = 列表第i项(数据列表)
设 CSV内容 = CSV内容 &
从字典 记录 获取 "name" & "," &
从字典 记录 获取 "age" & "," &
从字典 记录 获取 "city" & "\n"
设 i = i + 1
调用 File1.保存文件(CSV内容, "/sdcard/MyApp/export.csv")
读取CSV
当 File1.收到文本(内容)
设 行列表 = 分割文本(内容, "\n")
设 数据列表 = 创建空列表
设 i = 2 ' 跳过标题行
当 i ≤ 列表长度(行列表)
设 字段 = 分割文本(列表第i项(行列表), ",")
如果 列表长度(字段) ≥ 3
设 记录 = 创建字典(
"name" → 列表第1项(字段),
"age" → 列表第2项(字段),
"city" → 列表第3项(字段)
)
设 数据列表 = 添加列表项(数据列表, 记录)
设 i = i + 1
FileTools扩展
FileTools 扩展提供了更强大的文件操作能力。
核心功能
| 功能 | 方法 |
|---|---|
| 复制文件 | CopyFile(source, dest) |
| 移动文件 | MoveFile(source, dest) |
| 列出目录 | ListFiles(directory) |
| 创建目录 | MakeDir(path) |
| 删除目录 | DeleteDir(path) |
| 文件是否存在 | Exists(path) |
| 保存到相册 | SaveFileToGallery(path) |
| 扫描媒体文件 | ScanFile(path) |
使用示例
' 复制文件到相册
当 按钮_保存到相册.被点击
调用 FileTools1.复制文件(图片路径, "/sdcard/DCIM/Camera/photo_" & 时间戳 & ".png")
调用 FileTools1.扫描文件("/sdcard/DCIM/Camera/photo_" & 时间戳 & ".png")
' 列出目录文件
当 按钮_列出文件.被点击
调用 FileTools1.列出文件("/sdcard/MyApp/")
当 FileTools1.文件列表(文件列表)
设 显示 = ""
设 i = 1
当 i ≤ 列表长度(文件列表)
设 显示 = 显示 & 列表第i项(文件列表) & "\n"
设 i = i + 1
标签_文件列表.文本 = 显示
存储照片
从Camera保存到指定路径
当 按钮_拍照.被点击
调用 相机1.拍照()
当 相机1.拍照完成(图片路径)
' 复制到自己的目录
设 新路径 = "/sdcard/MyApp/photos/" & Clock1.格式化日期时间(Clock1.当前时间(), "yyyyMMdd_HHmmss") & ".jpg"
调用 FileTools1.复制文件(图片路径, 新路径)
标签_状态.文本 = "✅ 照片已保存:" & 新路径
存储到相册(通知系统刷新)
当 按钮_存相册.被点击
调用 FileTools1.保存到相册(图片路径)
' FileTools会自动通知系统扫描
已知问题:部分设备保存到相册后需要重启手机才可见。使用
ScanFile方法可以触发系统媒体扫描。
常见问题
Q1: 保存文件时提示权限拒绝?
Android 6.0+需要动态申请存储权限。在Screen1的Properties中设置:
ReadWriteExternalStorage= true
Q2: 如何判断文件是否存在?
使用FileTools扩展的 Exists 方法,或者尝试读取文件:
调用 File1.读取文件(目标路径)
当 File1.收到文本(内容)
如果 内容 = ""
标签_状态.文本 = "文件不存在或为空"
否则
标签_状态.文本 = "文件存在"
Q3: 如何处理大文件?
- 读取大文件(>1MB)可能导致App卡顿
- 使用分块读取或只读取需要的部分
- 图片文件直接用Image组件加载路径,不需要用File读取
Q4: FileTools扩展保存到相册需要重启?
这是Android媒体扫描机制的已知问题。解决方案:
- 调用
ScanFile主动触发扫描 - 使用
MediaStoreAPI(需要扩展支持) - 接受这个限制,告知用户稍等片刻
总结
| 需求 | 组件/方法 | 推荐 |
|---|---|---|
| 简单读写 | File组件 | ✅ |
| 复制/移动/目录 | FileTools扩展 | ✅ |
| 保存到相册 | FileTools | ✅ |
| CSV导出 | File + 文本处理 | ✅ |
| JSON数据 | File + 字典 | ✅ |
| 大文件处理 | WebView + JS | 高级 |
版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。
扫码添加客服咨询