一、实验简介
本案例基于微信小程序文件系统,实现写文件、复制文件、读文件、获取文件信息四大文件操作,并扩展实现删除文件。运行后可在textarea中录入文字,点击按钮对本地用户文件进行增删改查,信息显示区实时反馈操作结果。
开发环境:微信开发者工具,渲染引擎:skyline 核心 API:
wx.getFileSystemManager()、writeFile、copyFile、readFile、getFileInfo、unlink
二、项目目录结构
文件操作 ├── app.js ├── app.json ├── app.wxss ├── components │ └── navigation-bar # 自定义导航栏 └── pages └── index ├── index.js ├── index.wxml └── index.wxss三、文件系统基础概念
1. 获取文件管理器
文件系统是小程序提供的一套以小程序和用户维度隔离的存储及管理接口。通过wx.getFileSystemManager()获取全局唯一的文件管理器,所有文件操作都通过它调用:
const fs = wx.getFileSystemManager()2. 文件的两大类
表格
| 类型 | 说明 |
|---|---|
| 代码包文件 | 在项目目录中添加的文件,随代码包一起发布 |
| 本地文件 | 通过接口本地产生,或从网络下载后存储到本地的文件 |
3. 本地文件的三种形式
- 本地临时文件:临时产生,随时可能被回收;
- 本地缓存文件:由临时文件缓存产生,不能自定义目录和文件名;
- 本地用户文件:由临时文件缓存产生,允许自定义目录和文件名(功能更完整,推荐使用)。
4. 本地文件的沙箱隔离
本地文件以用户维度隔离:同一台手机,不同微信用户不能互相访问文件,同一用户不同 appId 之间也不能互相访问,充分保障用户隐私安全。
5. 用户文件路径wx.env.USER_DATA_PATH
const filePath = `${wx.env.USER_DATA_PATH}/hello.txt`- 使用模板字符串(反引号 ``)拼接路径,不要用引号
''; wx.env.USER_DATA_PATH表示文件系统中的用户目录(本地路径);- 路径格式为
协议名://文件路径,模拟器为http,真机 iOS/Android 为wxfile,开发者无需关心差异,不要在代码中硬编码完整路径。
四、代码
index.wxml
<!--index.wxml--> <navigation-bar title="文件操作" back="{{false}}" color="black" background="#FFF"></navigation-bar> <scroll-view class="scrollarea" scroll-y type="list"> <view class="box"> <view class="title">{{title}}</view> <textarea placeholder="请录入写入文件的内容" bind:input="inputText" /> <view class="btn-layout"> <button type="primary" size="mini" bind:tap="write">写文件</button> <button type="primary" size="mini" bind:tap="copy">复制文件</button> <button type="primary" size="mini" bind:tap="read">读文件</button> <button type="primary" size="mini" bind:tap="getFileInfo">文件信息</button> </view> <!-- 作业扩展:删除文件 --> <view class="extend-btn"> <button type="primary" size="mini" bind:tap="del">删除文件</button> </view> <view class="msg-area">{{msg}}</view> </view> </scroll-view>index.wxss/app.wxss
/* index.wxss */ textarea { width: auto; margin-bottom: 40rpx; padding: 20rpx; font-size: 40rpx; background-color: lightgoldenrodyellow; /* 淡金黄色输入区 */ } .btn-layout { display: flex; } .extend-btn { margin-top: 20rpx; display: flex; justify-content: center; } .msg-area { width: auto; height: 360rpx; margin-top: 40rpx; padding: 20rpx; font-size: 40rpx; background-color: azure; /* 淡蓝色信息区 */ }/* app.wxss */ .box { margin: 20rpx; padding: 20rpx; border: 2rpx solid purple; } .title { font-size: 40rpx; font-weight: bolder; text-align: center; margin-bottom: 30rpx; color: red; }index.js
1. 数据与输入监听
Page({ data: { title: '文件操作', msg: '', writedText: '' }, // 输入文字 inputText(e) { console.log(e); this.setData({ title: '正在输入文字...', writedText: e.detail.value }) },2. 写文件
// 写文件 write() { const fs = wx.getFileSystemManager() // 模拟器打印 http://usr,真机打印 wxfile://usr console.log(wx.env.USER_DATA_PATH); // 注意:使用反引号,即模板字符串 const filePath = `${wx.env.USER_DATA_PATH}/hello.txt` console.log(filePath); fs.writeFile({ filePath, data: this.data.writedText, // 写入 textarea 中录入的文字 encoding: 'utf-8', // 指定字符编码 success: res => { const msg = '写入文件成功: ' + filePath this.setData({ title: '写文件', msg }) }, fail: err => { console.log('写入文件识别' + err); } }) },3. 复制文件
// 复制文件 copy() { const fs = wx.getFileSystemManager() const srcPath = `${wx.env.USER_DATA_PATH}/hello.txt` console.log(srcPath); const destPath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` console.log(destPath); fs.copyFile({ srcPath, // 源文件路径 destPath, // 目标文件路径 success: res => { const msg = '复制文件成功: ' + destPath this.setData({ title: '复制文件', msg }) }, fail: err => { console.log('复制文件失败...' + err); } }) },4. 读取文件
// 读文件 read() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` console.log(filePath); fs.readFile({ filePath, encoding: 'utf-8', success: res => { // 读取到的内容在 res.data 中 const msg = '读取文件成功: ' + res.data this.setData({ title: '读文件', msg }) }, fail: err => { console.log('读取文件失败' + err); } }) },5. 获取文件信息
// 获取文件信息 getFileInfo() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` console.log(filePath); fs.getFileInfo({ filePath, success: res => { // res.size 文件大小,res.digest 文件摘要 const msg = `file size: ${res.size}, file digest: ${res.digest}` this.setData({ title: '获取文件信息', msg }) }, fail: err => { console.log('获取文件信息失败' + err); } }) }, // 作业扩展:删除文件(删除复制的文件) del() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` console.log(filePath); fs.unlink({ filePath, success: res => { const msg = '删除文件成功: ' + filePath this.setData({ title: '删除文件', msg }) }, fail: err => { console.log('删除文件失败' + err); } }) } })五、运行效果
- 初始界面:淡黄色
textarea+ 四个基础按钮 + 蓝色信息显示区; - 输入文字:标题变为 "正在输入文字...";
- 写文件:点击后把文字写入
hello.txt,显示 "写入文件成功" 及完整路径; - 复制文件:把
hello.txt复制为hello_copy.txt; - 读文件:读取
hello_copy.txt,在信息区显示文件内容; - 文件信息:显示
file size(文件大小)和file digest(文件摘要); - 删除文件(扩展):点击删除复制的
hello_copy.txt。
六、踩坑记录
问题 1:路径拼接用了引号导致路径错误
原因:误用单引号拼接,如wx.env.USER_DATA_PATH + '/hello.txt'或加了空格。解决:统一使用模板字符串反引号\${wx.env.USER_DATA_PATH}/hello.txt``。
问题 2:模拟器与真机路径不一致
现象:模拟器能读写,真机报错。原因:协议名不同,模拟器为http://usr,真机为wxfile://usr。解决:始终用wx.env.USER_DATA_PATH,不硬编码完整路径,交给平台自动适配。
问题 3:读文件内容是乱码或空
原因:未指定encoding,或写入 / 读取编码不一致。解决:读写统一指定encoding: 'utf-8'。
问题 4:读文件前没有先写 / 复制文件
现象:直接点 "读文件" 报错(文件不存在)。解决:遵循操作顺序 —— 先写文件,再复制文件,然后读文件 / 文件信息才有数据。读 / 获取信息操作的是hello_copy.txt,必须先复制。
问题 5:删除的是哪个文件
注意:作业要求删除 "复制的文件",所以del()操作hello_copy.txt,而不是源文件hello.txt。
七、知识点总结
- 所有文件操作统一通过
wx.getFileSystemManager()获取的文件管理器调用; - 路径必须用模板字符串拼接
wx.env.USER_DATA_PATH,协议名差异由平台自动适配,不要硬编码路径; - 文件操作是异步回调(success/fail),结果通过回调函数获取,不要在调用后同步读取;
- 本地文件以用户维度沙箱隔离,不同用户、不同 appId 之间不可互访;
writeFile写入、copyFile复制、readFile读取(内容在res.data)、getFileInfo取信息(res.size/res.digest)、unlink删除。