飞书小程序下载文件相关API(本地、Storage)

场景描述

在飞书小程序中,调用后端下载请求API下载文件,期望可以保存在手机本地/飞书本地/飞书临时目录/飞书缓存

在网络上找的下载url,在后端还没给API之前测试用的:
http://files.cnblogs.com/MolbyHome/%E6%83%B3%E6%B3%95.rar
https://cdn.jsdelivr.net/gh/belaviyo/download-with/samples/sample.zip

文件系统

飞书小程序文件系统:https://open.feishu.cn/document/client-docs/gadget/-web-app-api/file/file-system

本地临时文件(以ttfile://temp开头):临时产生,小程序重启会被清空的文件。
本地用户文件(以ttfile://user开头):小程序通过接口把本地临时文件保存后产生的文件,每个小程序最多可存储 200MB。

选择手机本地文件系统的文件

用到的飞书小程序接口tt.filepicker
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/file/filepicker

index.mpx

1
2
3
4
5
6
7
8
9
10
11
<template>
<view>
<view class="container">
打开手机本地文件系统
<button bindtap="openFileSystem">选择本地文件</button>
</view>
</view>
</template>

<script lang="ts" src="./index.ts">
</script>

index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import mpx, { createPage } from "@mpxjs/core";

createPage({
data: {
chooseFile: {},
},

methods: {
// 打开手机本地文件系统,选择文件后,这里会把文件存到飞书临时目录下 ttfile://temp
openFileSystem() {
console.log("打开文件系统,选择目标文件");
tt.filePicker({
maxNum: 10,
pickerTitle: "Select a file",
pickerConfirm: "Confirm",
isSystem: false,
success: (res) => {
console.log(res);
this.chooseFile = res.list[0];
},
fail: (res) => {
console.log("filePicker fail:", res);
},
});
},
},
});

page-img1

下载并存储到Storage

请求下载时responseType为arraybuffer,并且把文件存在Storage。
page-img3

Storage简介

飞书官网:https://open.feishu.cn/document/client-docs/gadget/-web-app-api/cache/local-data-cache

小程序可以通过下面列出的API读取、写入、删除、清理本地缓存数据,与 LocalStorage 类似。

以「键值对」的形式设置本地缓存数据。

单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB,同时也受到用户设备存储空间、缓存清理等机制的限制,可能会导致信息丢失,因此请不要将重要数据存放在本地数据缓存。

setStorage
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/cache/setstorage

1
2
3
4
5
6
7
8
9
10
tt.setStorage({
key: "name",
data: "小王",
success(res) {
console.log(JSON.stringify(res));
},
fail(res) {
console.log(`setStorage fail: ${JSON.stringify(res)}`);
}
});

getStorage
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/cache/getstorage

1
2
3
4
5
6
7
8
9
tt.getStorage({
key: "name",
success(res) {
console.log(JSON.stringify(res));
},
fail(res) {
console.log(`getStorage fail: ${JSON.stringify(res)}`);
}
});

更多接口请前往官网查看:

https://open.feishu.cn/document/client-docs/gadget/-web-app-api/cache/local-data-cache

  • getStorage
  • getStorageSync
  • setStorage
  • setStorageSync
  • removeStorage
  • removeStorageSync
  • clearStorage
  • clearStorageSync
  • getStorageInfo
  • getStorageInfoSync

下载文件存到Storage

用到的接口

tt.request:
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/network/initiating-request/request

tt.setStorage:https://open.feishu.cn/document/client-docs/gadget/-web-app-api/cache/setstorage

tt.getStorage:
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/cache/getstorage

index.mpx

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<view>
<view class="container">
下载文件,存到Storage (ArrayBuffer)
<button bindtap="onDownloadStorage" style="background-color: #55efc4">下载文件</button>
<button bindtap="readStorageFile">读取文件</button>
</view>
</view>
</template>

<script lang="ts" src="./index.ts">
</script>

index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import mpx, { createPage } from "@mpxjs/core";

createPage({
methods: {
// 下载文件,类型为ArrayBuffer,存到Storage
onDownloadStorage() {
const url =
"https://freetestdata.com/wp-content/uploads/2021/09/Free_Test_Data_200KB_CSV-1.csv";
console.log("下载文件===");
// 类型为arraybuffer
tt.request({
url,
responseType: "arraybuffer",
success: (res) => {
if (res.data) {
console.log("download file success", res);
const { data: arraybuffer } = res;
const byteArr = new Uint8Array(arraybuffer);
const arr = Array.from(byteArr);
// 保存为Array
tt.setStorage({
key: 'test-file',
data: arr,
success: (res) => {
console.log("setStorage success", res);
},
fail: (res) => {
console.error("setStorage fail", res);
},
});
}
},
fail: (err) => {
console.error("download file fail", err);
},
});
},

// 读取存到Storage的文件
readStorageFile() {
// 获取本地缓存数据的相关信息:
// 1.所有键名列表
// 2.占用空间大小,以 KB 为单位
// 3.存储空间上限,以 KB 为单位,一般来说会返回 10240
try {
const result = tt.getStorageInfoSync();
console.log(`缓存信息 success: ${JSON.stringify(result)}`);
} catch (error) {
console.log(`缓存信息 fail: ${JSON.stringify(error)}`);
}

// 根据key值读取相应的缓存数据
tt.getStorage({
key: 'test-file',
success: (res) => {
console.log("getStorage success。",res);
},
fail: (res) => {
console.error("getStorage fail", res);
},
});
},
},
});

飞书小程序下载文件并存到Storage
page-img4
飞书小程序的Storage出现了缓存数据
page-img5

下载到飞书本地临时目录

用到的飞书小程序接口tt.downloadFile
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/network/download/downloadfile

index.mpx

1
2
3
4
5
6
7
8
9
10
11
<template>
<view>
<view class="container">
下载文件,存到临时目录
<button bindtap="onDownload" style="background-color: #55efc4">下载文件</button>
</view>
</view>
</template>

<script lang="ts" src="./index.ts">
</script>

index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import mpx, { createPage } from "@mpxjs/core";
createPage({
methods: {
// 下载文件,存到临时目录
onDownload() {
console.log("下载文件");
tt.downloadFile({
url: "http://files.cnblogs.com/MolbyHome/%E6%83%B3%E6%B3%95.rar",
success: (res) => {
console.log(res);
},
fail: (res) => {
console.log("downloadFile fail:", res);
},
});
},
},
});

page-img2

下载到飞书本地目录

注意:这里的本地目录是指飞书提供的隔离空间ttfile://user/,不是手机系统本地目录。

方法:
飞书调用了downloadFileAPI只能把文件下载到临时目录,不能直接飞书本地目录。
但是飞书可以把临时目录中的文件存到飞书本地目录tt.saveFile

tt.saveFile: 该 API 会把临时文件移动到永久目录(目录最大200M),所以在调用成功后原文件路径将访问失败。
https://open.feishu.cn/document/client-docs/gadget/-web-app-api/file/file_system_manager/file_system_manager_save_file

因此,这里可以先把文件下载到临时目录,再把飞书临时目录中的文件存到飞书本地目录

index.mpx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<template>
<view >
<!-- fix 垂直塌陷 -->
<view style="content: ''; overflow: hidden;"></view>

<view style="color:blue;margin:30px">
<button bindtap="downloadFile">下载文件并保存到本地</button>
<button bindtap="openDir">打印/user/所有文件列表</button>
<button bindtap="clearDir">清空本地文件</button>
</view>
</view>
</template>

<script>
import { createPage } from '@mpxjs/core'

createPage({
methods: {
// 打印本地目录下所有文件的名称
openDir() {
const fileSystemManager = tt.getFileSystemManager()
try {
const files = fileSystemManager.readdirSync('ttfile://user/')
console.log('调用成功', files)
} catch (err) {
console.log('调用失败', err)
}
},

// 下载文件
downloadFile() {
wx.showLoading({
title: '下载中'
})
const file = {
name:'file-1.bin',
size: 21.3,
version: 'V3.1',
date: '2023/01/21'
},

console.log('下载升级文件')
// 下载文件,存到临时目录
tt.downloadFile({
url: 'https://cdn.jsdelivr.net/gh/belaviyo/download-with/samples/sample.zip',
success: (res) => {
console.log('存到临时目录', res)
const tempFilePath = res.tempFilePath

// 把文件从临时目录保存到本地目录
if (res.statusCode === 200 && tempFilePath) {
tt.saveFile({
tempFilePath,
filePath: 'ttfile://user/' + file.name,
success: (res) => {
console.log(`${JSON.stringify(res)}`)
},
fail: (res) => {
console.log(`saveFile fail: ${JSON.stringify(res)}`)
}
})
}
wx.hideLoading()
},
fail: (res) => {
console.log('downloadFile fail:', res)
wx.hideLoading()
}
})
},

// 删除本地目录的文件
removeSavedFile(fileList) {
const fileSystemManager = tt.getFileSystemManager()
fileList.forEach((file) => {
console.log('准备删除文件:', JSON.stringify(file))
fileSystemManager.removeSavedFile({
filePath: file.filePath,
success: (res) => {
console.log(`${file.filePath} 删除成功`)
},
fail: (res) => {
console.error(`${file.filePath} 删除失败`, res.errMsg)
}
})
})
},

// 清空本地目录
// 先遍历本地目录的文件,再去删除这些文件
clearDir() {
console.log('清空本地目录文件')
const fileSystemManager = tt.getFileSystemManager()
fileSystemManager.getSavedFileList({
success: (res) => {
console.log('当前用户目录下的文件:', res)
this.removeSavedFile(res.fileList)
}
})
}
}
})
</script>

<style lang="scss">
</style>

  1. 下载文件到临时目录
  2. 把文件从临时目录保存到本地目录
  3. 打印本地目录下所有文件的名称
经过123步后的控制台输出
  1. 清空本地文件目录(先遍历本地目录的文件,再去删除这些文件)
清空本地文件目录的控制台输出