一、项目简介
本案例演示微信小程序FileSystemManager 文件管理器API,实现本地用户文件的:写文件、复制文件、读文件、获取文件信息。 作业扩展:新增删除文件按钮,实现删除复制出来的hello_copy.txt文件,页面标题与消息区域同步更新。
开发环境:微信开发者工具 新建项目配置:项目名
文件操作,不使用云服务、不使用模板,Skyline 渲染模式。
页面布局:
- 顶部标题区域
textarea文本输入框,用于录入待写入文件的文本- 功能按钮组:写文件、复制文件、读文件、文件信息、【扩展】删除文件
- 消息展示 view 区域,展示接口执行结果、文件路径、文件内容、文件大小摘要等信息。
知识点:小程序本地用户文件拥有沙箱隔离机制,不同用户、不同小程序 AppID 互相不能访问对方文件,保障隐私安全。
wx.env.USER_DATA_PATH:小程序用户文件根目录,模拟器路径前缀http://usr,真机前缀wxfile://usr,代码使用模板字符串拼接,不要硬编码协议头。
二、项目目录结构
文件操作 ├─ app.json # 全局配置 ├─ app.wxss # 全局公共样式 └─ pages └─ index ├─ index.js # 文件操作业务逻辑 ├─ index.wxml # UI页面结构 └─ index.wxss # 页面局部样式三、完整代码实现
1. app.json
{ "pages": [ "pages/index/index" ], "window": { "navigationBarTextStyle": "black", "navigationStyle": "custom" }, "style": "v2", "renderer": "skyline", "rendererOptions": { "skyline": { "defaultDisplayBlock": true, "defaultContentBox": true, "tagNameStyleIsolation": "legacy", "disableABTest": true, "sdkVersionBegin": "3.0.0", "sdkVersionEnd": "15.255.255" } }, "componentFramework": "glass‑easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents" }2. pages/index/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="btn‑layout"> <button type="primary" size="mini" bind:tap="deleteFile">删除文件</button> </view> <view class="msg‑area">{{msg}}</view> </view> </scroll-view>3. pages/index/index.wxss
page { height: 100vh; display: flex; flex-direction: column; } .scrollarea { flex: 1; overflow‑y: hidden; } textarea { width: auto; margin‑bottom: 40rpx; padding: 20rpx; font‑size: 40rpx; background‑color: lightgoldenrodyellow; } .btn‑layout { display: flex; justify‑content: space‑around; margin‑bottom:20rpx; } .msg‑area { width: auto; height: 360rpx; margin‑top: 40rpx; padding: 20rpx; font‑size: 40rpx; background‑color: azure; }4. 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; }5. pages/index/index.js(完整,含扩展删除文件)
Page({ data: { title: '文件操作', msg: '', writtenText: '' }, //输入框输入事件 inputText(e) { this.setData({ title: '正在输入文字...', writtenText: e.detail.value }) }, //写文件 writeFile write() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello.txt` fs.writeFile({ filePath, data: this.data.writtenText, encoding: 'utf‑8', success: res => { const msg = '写入文件成功:' + filePath this.setData({ title: '写文件', msg }) }, fail: err => { console.log('写入文件识别', err); } }) }, //复制文件 copyFile copy() { const fs = wx.getFileSystemManager() const srcPath = `${wx.env.USER_DATA_PATH}/hello.txt` const destPath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` fs.copyFile({ srcPath, destPath, success: res => { const msg = '复制文件成功:' + destPath this.setData({ title: '复制文件', msg }) }, fail: err => { console.log('复制文件失败...' + err); } }) }, //读取文件 readFile read() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` fs.readFile({ filePath, encoding: 'utf‑8', success: res => { const msg = '读取文件成功:' + res.data this.setData({ title: '读文件', msg }) }, fail: err => { console.log('读取文件失败' + err); } }) }, //获取文件信息 getFileInfo(大小、md5摘要digest) getFileInfo() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` fs.getFileInfo({ filePath, success: res => { const msg = `file size: ${res.size}, file digest: ${res.digest}` this.setData({ title: '获取文件信息', msg }) }, fail: err => { console.log('获取文件信息失败' + err); } }) }, //====作业扩展:删除文件 unlink 删除 hello_copy.txt ==== deleteFile() { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/hello_copy.txt` fs.unlink({ filePath, success: res => { const msg = '删除文件成功:' + filePath this.setData({ title: '删除文件', msg }) }, fail: err => { console.log("删除文件失败", err) this.setData({ msg: "删除文件失败:" + err.errMsg }) } }) } })四、小程序文件系统核心 API 汇总
表格
| API | 功能说明 |
|---|---|
wx.getFileSystemManager() | 获取全局唯一文件系统管理器 fs,所有文件操作都由 fs 调用 |
wx.env.USER_DATA_PATH | 用户本地文件根目录路径,模拟器与真机协议前缀不一样,使用模板字符串拼接 |
fs.writeFile({filePath,data,encoding}) | 写文件,将文本写入本地用户文件 |
fs.copyFile({srcPath,destPath}) | 复制文件,源文件→目标文件 |
fs.readFile({filePath,encoding}) | 读文件,读取本地文本文件内容,success 回调 res.data 拿到文本 |
fs.getFileInfo({filePath}) | 获取文件信息:size文件字节大小、digestmd5 摘要 |
fs.unlink({filePath}) | 删除文件(作业扩展 API),删除指定本地用户文件 |
文件分类
- 代码包文件:项目工程里自带的文件,只读,不能写入修改。
- 本地文件:程序运行动态生成,分为临时文件、缓存文件、用户文件(USER_DATA_PATH),用户文件支持自定义文件名。
⚠️沙箱隔离:每个微信用户、每个小程序 AppID 都拥有独立文件存储区域,互相不可访问,保障用户隐私。
五、开发踩坑总结
- 路径字符串引号错误拼接
filePath必须使用反引号`(模板字符串),不要用单引号' '。 - 模拟器和真机路径前缀不同 模拟器路径开头
http://usr;真机wxfile://usr;代码不要硬编码前缀,直接使用wx.env.USER_DATA_PATH拼接。 - 删除 / 复制 / 读取时报文件不存在
需要先执行【写文件】生成
hello.txt,再复制得到hello_copy.txt;没有生成源文件直接调用接口会触发 fail 失败回调。
- readFile 不设置 encoding 返回二进制 ArrayBuffer 读取文本文件,参数
encoding:'utf‑8'必须写,否则拿到的不是字符串文本。 - unlink 只能删除本地用户文件,不能删除项目代码包里的静态资源。