前言
应用沙箱是一种以安全防护为目的的隔离机制,避免数据受到恶意路径穿越访问。在这种沙箱的保护机制下,应用可见的目录范围即为“应用沙箱目录”。
●对于每个应用,系统会在内部存储空间映射出一个专属的“应用沙箱目录”,它是“应用文件目录”与一部分系统文件(应用运行必需的少量系统文件)所在的目录组成的集合。
●应用沙箱限制了应用可见的数据的最小范围。在“应用沙箱目录”中,应用仅能看到自己的应用文件以及少量的系统文件(应用运行必需的少量系统文件)。因此,本应用的文件也不为其他应用可见,从而保护了应用文件的安全。
●应用可以在“应用文件目录”下保存和处理自己的应用文件;系统文件及其目录对于应用是只读的;而应用若需访问用户文件,则需要通过特定API同时经过用户的相应授权才能进行。
应用文件目录与应用文件路径
如前文所述,“应用沙箱目录”内分为两类:应用文件目录和系统文件目录。
系统文件目录对应用的可见范围由系统预置,开发者无需关注。
在此主要介绍应用文件目录,如下图所示。应用文件目录下某个文件或某个具体目录的路径称为应用文件路径。应用文件目录下的各个文件路径,具备不同的属性和特征。
应用文件目录结构图
●获取沙箱目录
getContext().cacheDir
getContext().fileDir
getContext().tempDir
●文件操作
// harmonyOS提供文件操作的API,相当于nodejs的中的fs操作
// 注意: 在API9中 使用fs
// 在API11和API12中官方又提供了 fileIO的基础方法,用法和fs基本一致,实际导出的就是API9中的fs
open 打开文件
close 关闭文件
write写入文件
copy 复制文件
unlink 删除文件
mkdir 创建文件夹
// 上述方法均支持promise并提供有对应的同步方法
// 想要操作一个文件,首先要打开一个文件,读取一个文件的buffer或者fd,通过fd进行文件的buffer进行相应的操作
●沙箱目录的内容 图片或者web组件要去访问的,需要使用文件协议
file://
●代码演示下载网络图片
async downLoad () {
let path = getContext().cacheDir + '/' + Date.now() + ".jpg"
const task = await request.downloadFile(getContext(),{
url: 'http://dingyue.ws.126.net/2024/0209/8ec94ea3g00s8l8ki00ytd200f0008cg00it00ag.gif',
filePath: path
})
task.on("progress", (process,total) => {
promptAction.showToast({
message: process + '-' + total
})
})
task.on("complete", () => {
this.tempPath = path
AlertDialog.show({
message: '下载成功'
})
})
}
●代码演示从相册选择图片、保存在沙箱并上传
// 导入图片选择器
import { picker } from '@kit.CoreFileKit'
// 导入文件操作库
import { fileIo } from '@kit.CoreFileKit'
// 选择图片
async selectImage() {
const photoPicker = new picker.PhotoViewPicker()
const result = await photoPicker.select({
// 图片类型
MIMEType: picker.PhotoViewMIMETypes.IMAGE_TYPE,
// 最多张数
maxSelectNumber: 9
})
// 选择的图片数组
if (!result.photoUris?.length) { return }
// 保存到沙箱cache目录
// 获取cache目录
const saveDir = getContext().cacheDir
// 构造上传文件需要的参数
const files: request.File[] = []
// 读取相册文件
result.photoUris.forEach(url => {
const file = fileIo.openSync(url, fileIo.OpenMode.READ_ONLY)
// 将文件拷贝到沙箱目录
const uniqueName = util.generateRandomUUID() + ".jpg"
fileIo.copyFileSync(file.fd, saveDir + "/" + uniqueName)
// 生成参数
files.push({
filename: uniqueName, // 文件名称
name: 'file', // 接口的参数名称
type: 'jpg', // 文件后缀
uri: `internal://cache/${uniqueName}` // 文件的路径,internal: 是固定写法
})
fileIo.close(file.fd)
})
// 上传
// 构造上传需要的参数
let config: request.UploadConfig = {
url: "", // 服务器上传图片的接口地址
method: 'POST',
header: {
"Authorization": "", // 身份验证标识,以服务器要求为准
"Content-Type": "multipart/form-data" // 请求体类型,表单类型
},
files,
data: [] // 批量上传需要的参数
}
// 上传完成,结果保存在list
try {
let list: list[] = []
const task = await request.uploadFile(context, config)
// 成功执行意味着任务创建成功,而不是上传成功
task.on("fail", () => {
// 上传失败
promptAction.showToast({ message: "上传失败"})
})
task.on("complete", () => {
// 上传成功
})
// 每上传成功一次就会进来,可以获取到上传成功的url
task.on("headerReceive", (header: object) => {
if (header["body"]) {
const result = JSON.parse(header["body"]) as ResponseData<string>
if (result.code === 200 && result.data) {
list.push(result.data)
}
}
})
} catch (error) {
promptAction.showToast({ message: error.message})
}
}
写在最后
●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing ,不定期分享原创知识。