uni-app 系统公共目的下的文件不支持移动和拷贝到沙盒目录?
uni-app 系统公共目的下的文件不支持移动和拷贝到沙盒目录?
| 开发环境 | 版本号 | 项目创建方式 |
|---|---|---|
| HBuilderX | 3.3.3 | 云端 |
示例代码:
moveCopyFileToDst: function(files, method, succCallback, errCallback) {
var _this = this,
result = [];
function copyfile(fileEntry, dstEntry, fileName, callback) {
fileEntry.copyTo(dstEntry, fileName, function(entry) {
callback(entry)
}, function(e) {
console.log(e.message + ' 有些文件路径不存在或无法复制')
errCallback(e.message)
})
}
function movefile(fileEntry, dstEntry, fileName, callback) {
console.log('movefile moveTo fileEntry.fullPath', fileEntry.fullPath)
console.log('movefile moveTo dstEntry.name', dstEntry.name)
console.log('movefile moveTo dstEntry.fullPath', dstEntry.fullPath)
console.log('movefile moveTo fileName', fileName)
fileEntry.moveTo(dstEntry, fileName, function(entry) {
callback(entry)
}, function(e) {
console.log(e.message)
errCallback(e.message)
})
}
/**
* 递归生成文件名
* @param {Object} fileName
* @param {Object} index
* @param {Object} callback
*/
function recursionCreateFileName(fileName, dstPath, index, callback) {
//目标文件存在,这行会与if (_this.fileExists(dstPath + newFileName)) {重复判断
// if (_this.fileExists(dstPath + fileName)) {
//生成一个新文件名: abc.txt abc(0).txt abc(1).txt
var split = fileName.split('.'),
newFileName = split[0] + '(' + index + ').' + split[1];
//再判断新生成的文件名是否存在,如果存在重新调用自己
if (_this.fileExists(dstPath + newFileName)) {
recursionCreateFileName(fileName, dstPath, index + 1, callback)
} else {
//不存在,返回新文件名
callback(newFileName)
}
// } else {
// callback(fileName)
// }
}
function recursion(files, index) {
if (index == files.length) {
return succCallback(result)
}
var originalFile = files[index],
fileSplit = originalFile.split('/'),
fileName = fileSplit[fileSplit.length - 1],
dstEntry = _this.getFileDirEntry(fileName);
console.log('原文件路径: ' + originalFile)
console.log('原文件名: ' + fileName)
console.log('目标文件目录: ' + dstEntry.fullPath + fileName)
console.log('目标文件路径: ' + dstEntry.name)
plus.io.resolveLocalFileSystemURL(dstEntry.fullPath + fileName, function(dstFileEntry) {
console.log('目标文件存在!' + dstFileEntry.fullPath)
plus.io.resolveLocalFileSystemURL(originalFile, function(fileEntry) {
if (method === 'move') {
recursionCreateFileName(fileName, dstEntry.fullPath, 0, function(filename) {
movefile(fileEntry, dstEntry, filename, function(ent) {
result.push(ent.fullPath);
recursion(index + 1)
})
})
}
if (method === 'copy') {
console.log('dstEntry copy path: ' + dstEntry.fullPath)
recursionCreateFileName(fileName, dstEntry.fullPath, 0, function(filename) {
copyfile(fileEntry, dstEntry, filename, function(ent) {
result.push(ent.fullPath);
recursion(index + 1)
})
})
}
})
}, function(e) {
console.log('目标文件不存在!')
plus.io.resolveLocalFileSystemURL(originalFile, function(fileEntry) {
if (method === 'move') {
console.log('dstEntry move path: ' + dstEntry.fullPath + fileName)
movefile(fileEntry, dstEntry, fileName, function(ent) {
result.push(ent.fullPath);
recursion(index + 1)
})
}
if (method === 'copy') {
console.log('dstEntry copy path: ' + dstEntry.fullPath + fileName)
copyfile(fileEntry, dstEntry, fileName, function(ent) {
result.push(ent.fullPath);
recursion(index + 1)
})
}
})
})
}
recursion(files, 0)
}
plus.gallery.pick(function(res) {
console.log('actionSheet pick files: ' + JSON.stringify(res))
_this.moveCopyFileToDst(res.files, 'move', function(res) {
}, function(err) {
})
},
function(e) {
console.log(JSON.stringify(e));
plus.nativeUI.closeWaiting()
}, config)
操作步骤:
- pick 选择图片。
- 勾选最下面的“原图”。
- 选图片。
- 判断
_doc/images下是否有该文件。如果不存在就移动到_doc/images下,存在就重新启个名字再移动到_doc/images下。
预期结果:
移动或复制成功
实际结果:
targetSdkVersion设置>=29后在Android10+系统设备不支持当前路径。请更改为应用运行路径!具体请看: https://ask.dcloud.net.cn/article/36199
bug描述:
系统公共目的下的文件 file:///storage/emulated/0/Download/1639293586409.jpg 不支持移动和拷贝到沙盒目录 /storage/emulated/0/Android/data/xx.xx.com/apps/H5AE01F30/doc/images/ 中?
更多关于uni-app 系统公共目的下的文件不支持移动和拷贝到沙盒目录?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
公共目的下的文件不支持移动到应用沙盒目录。正如错误信息提示
更多关于uni-app 系统公共目的下的文件不支持移动和拷贝到沙盒目录?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
您好,请问我怎么操作才行?压缩吗?
复制可以吗?
回复 矩信: plus.io不支持 你可以尝试使用uni原生插件来实现。直接使用原生代码实现
回复 DCloud_Android_ST: 我是 html plu5+ 开发的,也能用 uni 原生插件吗?请问怎么用?
刚才试了一下,move 不可以,copy 可以
换策略了,如果从相册返回的文件路径包含 uniapp_temp/compressed 说明不是原图是压缩后的,这个 moveTo() 支持,反之说明是原图,就用 copyTo(),uniapp_temp/compressed 用 moveTo 就对了,要不然会产生大量垃圾,除非自己专门写代码维护。
是的,在 Android 10(API 29)及以上版本,由于系统引入了作用域存储(Scoped Storage)的限制,应用无法直接通过文件路径(如 file:///storage/emulated/0/Download/...)访问和操作系统公共目录下的文件。这包括移动(moveTo)和复制(copyTo)操作。
您遇到的错误信息“系统公共目的下的文件不支持移动和拷贝到沙盒目录”正是这个原因。当 targetSdkVersion 设置为 29 或更高时,应用对公共目录的访问权限受到了更严格的管控。
核心问题与解决方案:
- 问题根源:您通过
plus.gallery.pick获取到的文件 URI(如file:///storage/emulated/0/Download/1639293586409.jpg)在 Android 10+ 上,应用仅拥有临时的读取权限。您无法直接使用plus.io的moveTo或copyTo方法将其操作到应用的私有沙盒目录(_doc)。 - 正确做法:必须使用 “先读取,再写入” 的方式。即:
- 通过获取到的文件 URI,使用
plus.io的相关 API 读取文件内容(例如,转换为Blob或ArrayBuffer)。 - 然后,在应用沙盒目录(如
_doc/images)下创建一个新文件。 - 最后,将读取到的内容写入到这个新创建的文件中。
- 通过获取到的文件 URI,使用
代码修改建议(关键部分):
替换您 moveCopyFileToDst 函数中对于公共目录文件的操作逻辑。以下是一个处理 copy 操作的示例思路:
// 假设 originalFile 是类似 `file:///storage/emulated/0/Download/xxx.jpg` 的路径
function copyPublicFileToSandbox(originalFile, dstDirEntry, fileName, callback) {
// 1. 读取公共目录文件内容
plus.io.resolveLocalFileSystemURL(originalFile, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
// 2. 在沙盒目标目录创建新文件
dstDirEntry.getFile(fileName, { create: true }, function(newFileEntry) {
// 3. 将内容写入新文件
newFileEntry.createWriter(function(writer) {
writer.onwriteend = function(e) {
callback(newFileEntry); // 操作成功,返回新文件Entry
};
writer.onerror = function(e) {
errCallback('写入文件失败: ' + e.toString());
};
// 将读取到的ArrayBuffer数据写入
var blob = new Blob([reader.result]);
writer.write(blob);
}, function(e) {
errCallback('创建Writer失败: ' + e.message);
});
}, function(e) {
errCallback('创建文件失败: ' + e.message);
});
};
reader.onerror = function(e) {
errCallback('读取文件失败: ' + e.toString());
};
reader.readAsArrayBuffer(file);
}, function(e) {
errCallback('获取File对象失败: ' + e.message);
});
}, function(e) {
errCallback('解析源文件路径失败: ' + e.message);
});
}

