import { WriteFileOptions, ReadFileOptions, MkDirOptions, RmDirOptions, TruncateFileOptions, UnLinkOptions, ReadDirOptions, AccessOptions, RenameOptions, GetFileInfoOptions, CopyFileOptions, StatOptions, AppendFileOptions, OpenFileOptions, OpenFileSuccessCallback, OpenFileSuccessResult, SaveFileOptions, UnzipFileOptions, GetSavedFileListOptions, ReadCompressedFileOptions, ReadCompressedFileResult, RemoveSavedFileOptions, WriteOptions, WriteResult, OpenFileSyncOptions, WriteSyncOptions, CloseOptions, CloseSyncOptions, FStatOptions, FStatSuccessResult, FTruncateFileOptions, FTruncateFileSyncOptions, FStatSyncOptions, ReadZipEntryOptions, ZipFileItem, ReadZipEntryCallback, EntriesResult } from "../interface.uts" import { ReadFileSuccessResult, FileManagerSuccessResult, ReadDirSuccessResult, AccessSuccessResult, SaveFileSuccessResult, GetFileInfoSuccessResult, StatSuccessResult, FileStats, Stats, GetSavedFileListResult } from "../interface.uts" import { GetFileSystemManager, FileSystemManager } from "../interface.uts" import { UniErrorSubject, UniErrors } from "../unierror.uts" import { FileDescriptorUtil } from "./FileDescriptorUtil" import File from "java.io.File" import Base64 from "android.util.Base64" import MessageDigest from 'java.security.MessageDigest'; import FileInputStream from 'java.io.FileInputStream'; import Charsets from "kotlin.text.Charsets" import FileOutputStream from 'java.io.FileOutputStream'; import ZipInputStream from 'java.util.zip.ZipInputStream'; import BufferedInputStream from 'java.io.BufferedInputStream'; import BrotliInputStream from 'org.brotli.dec.BrotliInputStream' import Build from 'android.os.Build' import Environment from 'android.os.Environment' import Option from 'android.app.VoiceInteractor.PickOptionRequest.Option'; import FileDescriptor from 'java.io.FileDescriptor'; import ParcelFileDescriptor from 'android.os.ParcelFileDescriptor'; import ByteBuffer from 'java.nio.ByteBuffer'; class AndroidStats implements Stats, io.dcloud.uts.log.LogSelf, io.dcloud.uts.json.IJsonStringify { /** * 文件的类型和存取的权限,对应 POSIX stat.st_mode * 注意android中,文件类型只包含是否是目录与文件, * 另外在android中这里的权限指的是当前进程对文件或者文件夹是否有读,写,执行的权限, * 这里没有与 POSIX stat.st_mode对应的组,其他人等相关权限的数据返回,只有所有者的相关权限 */ mode : number = 0; /** * 文件大小,单位:B,对应 POSIX stat.st_size */ size : number = 0; /** * 文件最近一次被存取或被执行的时间,UNIX 时间戳,对应 POSIX stat.st_atime * 注意:android中由于系统限制无法获取该数据 */ lastAccessedTime : number = 0; /** * 文件最后一次被修改的时间,UNIX 时间戳,对应 POSIX stat.st_mtime */ lastModifiedTime : number = 0; /** * @internal */ mIsFile : boolean = false; constructor() { } /** * 判断当前文件是否一个目录 */ isDirectory() : boolean { return !this.mIsFile } /** * 判断当前文件是否一个普通文件 */ isFile() : boolean { return this.mIsFile } /** * @internal */ override toLog() : any | null { return this.toJSON() } /** * @internal */ override toJSON() : any | null { let jsonRet = new UTSJSONObject() jsonRet.set("mode", this.mode) jsonRet.set("size", this.size) jsonRet.set("lastAccessedTime", this.lastAccessedTime) jsonRet.set("lastModifiedTime", this.lastModifiedTime) return jsonRet } } class AndroidFileSystemManager implements FileSystemManager { fileDesUtil : FileDescriptorUtil = new FileDescriptorUtil() private static manager : AndroidFileSystemManager = new AndroidFileSystemManager() private constructor() { } public static getManager() : AndroidFileSystemManager { return this.manager; } public stat(options : StatOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { currentDispatcher.async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.path) let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.path); options.fail?.(err) options.complete?.(err) }, null) return } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.path); options.fail?.(err) options.complete?.(err) }, null) return } if (options.recursive == true && targetFile.isDirectory()) { // 如果当前是目录,并且设置 则需要遍历所有子目录 let res : Array = [] /** * 与文件不同的是,需要迭代下属的文件 */ targetFile.walk() .onEnter(function (file : File) : boolean { if (file.isDirectory()) { return true } return false }) .iterator() .forEach(function (file : File) { let perFileStats : FileStats = { path: file.getPath(), stats: wrapStats(file) } res.add(perFileStats) }) let success : StatSuccessResult = { errMsg: "stat:ok", stats: res } options.success?.(success) options.complete?.(success) } else { // 默认是false,只读取当前一个文件 let mode = 0 let filesize = 0; let rootFileStats : FileStats = { path: targetFile.getPath(), stats: wrapStats(targetFile) } let res : Array = [rootFileStats] let success : StatSuccessResult = { errMsg: "stat:ok", stats: res } //new StatSuccessResult("stat:ok", res) options.success?.(success) options.complete?.(success) } }, null) }, null) } public statSync(path : string, recursive : boolean) : FileStats[] { let msgPrefix = "statSync:fail " let filePath = UTSAndroid.convert2AbsFullPath(path) let tempRecursive = recursive let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!); } if (tempRecursive == true && targetFile.isDirectory()) { // 如果当前是目录,并且设置 则需要遍历所有子目录 let res : Array = [] /** * 与文件不同的是,需要迭代下属的文件 */ targetFile.walk() .onEnter(function (file : File) : boolean { if (file.isDirectory()) { return true } return false }) .iterator() .forEach(function (file : File) { let perFileStats : FileStats = { path: file.getPath(), stats: wrapStats(file) } res.add(perFileStats) }) return res } else { // 默认是false,只读取当前一个文件 let mode = 0 let filesize = 0; let rootFileStats : FileStats = { path: targetFile.getPath(), stats: wrapStats(targetFile) } return [rootFileStats] } } public getFileInfo(options : GetFileInfoOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }, null) return } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }, null) return } if (targetFile.isDirectory()) { /** * 文件是个目录 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300021, UniErrors.get(1300021)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }, null) return } if (options.digestAlgorithm == null) { options.digestAlgorithm = "md5" } if (options.digestAlgorithm!.toLowerCase() != 'md5' && options.digestAlgorithm!.toLowerCase() != 'sha1') { /** * invalid digestAlgorithm */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300022, UniErrors.get(1300022)! + ":invalid digestAlgorithm " + options.digestAlgorithm); options.fail?.(err) options.complete?.(err) }, null) return } let md5Digest = MessageDigest.getInstance(options.digestAlgorithm!) let fileLen = targetFile.length() // 使用缓冲区读取文件内容 let buffer = new ByteArray(8192) let fis = new FileInputStream(targetFile) let len = 0 while (len != -1) { len = fis.read(buffer) if (len != -1) { md5Digest.update(buffer, 0, len.toInt()) } } fis.close(); let digestByte = md5Digest.digest(); // byte to string let strHexString = new StringBuffer(); // byte buffer for (let i = 0; i < digestByte.size; i++) { // 取0xff部分 let hex = Integer.toHexString(0xff & digestByte[i.toInt()].toInt()); if (hex.length == 1) { strHexString.append('0'); } strHexString.append(hex); } // 得到返回結果 let sign = strHexString.toString(); currentDispatcher.async(function (_) { let success : GetFileInfoSuccessResult = { digest: sign, size: fileLen, errMsg: "getFileInfo:ok" } options.success?.(success) options.complete?.(success) }, null) }, null) } public copyFileSync(srcPath : string, destPath : string) : void { // 检查来源文件 let msgPrefix = "copyFileSync:fail " let filePath = UTSAndroid.convert2AbsFullPath(srcPath) if (filePath.startsWith("/android_asset/")) { // 用户访问的是asset 路径,此时不是释放模式 let byteArray : ByteArray try { let assetName = filePath.substring("/android_asset/".length) let assetStream = UTSAndroid.getAppContext()!.getResources().getAssets().open(assetName); let byteLen = assetStream.available(); byteArray = new ByteArray(byteLen) assetStream.read(byteArray); } catch (e) { throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!); } // 检查目标文件 let newFilePath = UTSAndroid.convert2AbsFullPath(destPath) let isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!); } let newFile = new File(newFilePath) if (newFile.getParentFile() != null && !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } newFile.writeBytes(byteArray) if (!newFile.exists()) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } else { let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } // 检查目标文件 let newFilePath = UTSAndroid.convert2AbsFullPath(destPath) isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let newFile = new File(newFilePath) if (newFile.getParentFile() != null && !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } let copyRetFile = targetFile.copyTo(newFile, true) if (!copyRetFile.exists()) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } } public copyFile(options : CopyFileOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { // 检查来源文件 let filePath = UTSAndroid.convert2AbsFullPath(options.srcPath) if (filePath.startsWith("/android_asset/")) { // 用户访问的是asset 路径,此时不是释放模式 let exceptionInfo : Exception | null = null let byteArray = new ByteArray(0) try { let assetName = filePath.substring("/android_asset/".length) let assetStream = UTSAndroid.getAppContext()!.getResources().getAssets().open(assetName); let byteLen = assetStream.available(); byteArray = new ByteArray(byteLen) assetStream.read(byteArray); } catch (e : Exception) { exceptionInfo = e } if (exceptionInfo != null) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + exceptionInfo.message); options.fail?.(err) options.complete?.(err) }, null) return } // 检查目标文件 let newFilePath = UTSAndroid.convert2AbsFullPath(options.destPath) let isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.destPath); options.fail?.(err) options.complete?.(err) }, null) return } let newFile = new File(newFilePath) if (newFile.getParentFile() != null && !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.destPath); options.fail?.(err) options.complete?.(err) }, null) return } newFile.writeBytes(byteArray) if (!newFile.exists()) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)!); options.fail?.(err) options.complete?.(err) }, null) return } currentDispatcher.async(function (_) { let success : FileManagerSuccessResult = { errMsg: "copyFile:ok" } options.success?.(success) options.complete?.(success) }, null) } else { let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.srcPath); options.fail?.(err) options.complete?.(err) }, null) return } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.srcPath); options.fail?.(err) options.complete?.(err) }, null) return } // 检查目标文件 let newFilePath = UTSAndroid.convert2AbsFullPath(options.destPath) isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.destPath); options.fail?.(err) options.complete?.(err) }, null) return } let newFile = new File(newFilePath) if (newFile.getParentFile() != null && !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.destPath); options.fail?.(err) options.complete?.(err) }) return } let copyRetFile = targetFile.copyTo(newFile, true) if (!copyRetFile.exists()) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)!); options.fail?.(err) options.complete?.(err) }) return } currentDispatcher.async(function (_) { let success : FileManagerSuccessResult = { errMsg: "copyFile:ok" } options.success?.(success) options.complete?.(success) }) } }, null) } public renameSync(oldPath : string, newPath : string) : void { let msgPrefix = "renameSync:fail " let filePath = UTSAndroid.convert2AbsFullPath(oldPath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1301003)!); } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } let newFilePath = UTSAndroid.convert2AbsFullPath(newPath) isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let newFile = new File(newFilePath) if (newFile.getParentFile() == null || !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } let renameRet = targetFile.renameTo(newFile) if (!renameRet) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } public rename(options : RenameOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.oldPath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.oldPath); options.fail?.(err) options.complete?.(err) }) return } let targetFile = new File(filePath) if (!targetFile.exists()) { /** * 文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.oldPath); options.fail?.(err) options.complete?.(err) }) return } let newFilePath = UTSAndroid.convert2AbsFullPath(options.newPath) isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.newPath); options.fail?.(err) options.complete?.(err) }) return } let newFile = new File(newFilePath) if (newFile.getParentFile() == null || !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.newPath); options.fail?.(err) options.complete?.(err) }) return } let renameRet = targetFile.renameTo(newFile) if (!renameRet) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)!); options.fail?.(err) options.complete?.(err) }) return } currentDispatcher.async(function (_) { let success : FileManagerSuccessResult = { errMsg: "rename:ok" } options.success?.(success) options.complete?.(success) }) }, null) } public accessSync(path : string) : void { let msgPrefix = "accessSync:fail " let filePath = UTSAndroid.convert2AbsFullPath(path) let targetFile = new File(filePath) let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } if (!targetFile.exists()) { /** * 文件不存在,或者不是文件夹,异常 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } } public access(options : AccessOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.path) let targetFile = new File(filePath) let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.path); options.fail?.(err) options.complete?.(err) }) return } if (!targetFile.exists()) { /** * 文件不存在,或者不是文件夹,异常 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.path); options.fail?.(err) options.complete?.(err) }) return } currentDispatcher.async(function (_) { // 成功 let success : FileManagerSuccessResult = { errMsg: "access:ok" } options.success?.(success) options.complete?.(success) }) }, null) } readdirSync(dirPath : string) : string[] | null { let msgPrefix = "readdirSync:fail " let filePath = UTSAndroid.convert2AbsFullPath(dirPath) let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let targetFile = new File(filePath) if (!targetFile.exists() || !targetFile.isDirectory()) { /** * 文件不存在,或者不是文件夹,异常 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } return UTSArray.fromNative(targetFile.list()!) } public readdir(options : ReadDirOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.dirPath) let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } let targetFile = new File(filePath) if (!targetFile.exists() || !targetFile.isDirectory()) { /** * 文件不存在,或者不是文件夹,异常 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } let success : ReadDirSuccessResult = { files: UTSArray.fromNative(targetFile.list()!) } currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }) }, null) } public rmdirSync(dirPath : string, recursive : boolean) : void { let msgPrefix = "rmdirSync:fail " let filePath = UTSAndroid.convert2AbsFullPath(dirPath) let targetFile = new File(filePath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } if (!targetFile.exists() || !targetFile.isDirectory()) { /** * 文件不存在 或者 文件是不是文件夹 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } if (!recursive) { // 没有设置递归,则需要检查是否保存子目录 let childList = targetFile.list() if (childList != null && childList.size > 0) { // 存在子目录 throw new UniError(UniErrorSubject, 1300066, msgPrefix + UniErrors.get(1300066)!) } } else { let delRet = targetFile.deleteRecursively() if (!delRet) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } } public mkdirSync(dirPath : string, recursive : boolean) : void { let msgPrefix = "mkdirSync:fail " if (dirPath.isEmpty()) { throw new UniError(UniErrorSubject, 1300066, msgPrefix + UniErrors.get(1300066)!) } let filePath = UTSAndroid.convert2AbsFullPath(dirPath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let targetFile = new File(filePath) if (targetFile.exists()) { /** * 文件已经存在,则无法继续创建 */ throw new UniError(UniErrorSubject, 1301005, msgPrefix + UniErrors.get(1301005)!) } if (!recursive) { // 没有设置递归创建 if (targetFile.getParentFile() == null || !targetFile.getParentFile()!.exists()) { throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } else { // 父文件夹存在,则继续创建 let mkRet = targetFile.mkdir() if (!mkRet) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } } else { // 设置了递归 let mkRet = targetFile.mkdirs() if (!mkRet) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } } public rmdir(options : RmDirOptions) { let filePath = UTSAndroid.convert2AbsFullPath(options.dirPath) let targetFile = new File(filePath) let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } if (!targetFile.exists() || !targetFile.isDirectory()) { /** * 文件不存在 或者 文件是不是文件夹 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } if (!options.recursive) { // 没有设置递归,则需要检查是否保存子目录 let childList = targetFile.list() if (childList != null && childList.size > 0) { // 存在子目录 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300066, UniErrors.get(1300066)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } } else { let delRet = targetFile.deleteRecursively() if (!delRet) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } } let success : FileManagerSuccessResult = { errMsg: "rmdir:ok" } // 删除成功 currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }) }, null) } public mkdir(options : MkDirOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { if (options.dirPath.isEmpty()) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300066, UniErrors.get(1300066)!); options.fail?.(err) options.complete?.(err) }) return } let filePath = UTSAndroid.convert2AbsFullPath(options.dirPath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } let targetFile = new File(filePath) if (targetFile.exists()) { /** * 文件已经存在,则无法继续创建 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1301005, UniErrors.get(1301005)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } if (!options.recursive) { // 没有设置递归创建 if (targetFile.getParentFile() == null || !targetFile.getParentFile()!.exists()) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } else { // 父文件夹存在,则继续创建 let mkRet = targetFile.mkdir() if (!mkRet) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } } } else { // 设置了递归 let mkRet = targetFile.mkdirs() if (!mkRet) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + options.dirPath); options.fail?.(err) options.complete?.(err) }) return } } currentDispatcher.async(function (_) { let success : FileManagerSuccessResult = { errMsg: "mkdir:ok" } // 删除成功 options.success?.(success) options.complete?.(success) }) }, null) } unlinkSync(filePath : string) : void { let msgPrefix = "unlinkSync:fail " let temFilePath = UTSAndroid.convert2AbsFullPath(filePath) let isSandyBox = isSandyBoxPath(temFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let targetFile = new File(temFilePath) if (!targetFile.exists()) { throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } // 文件存在,则进行删除操作 let delRet = targetFile.delete() if (!delRet) { // 调用系统api 删除失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } } public unlink(options : UnLinkOptions) { /** * 遗留问题,无法知道是否属于沙盒路径 */ let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }) return } let targetFile = new File(filePath) if (!targetFile.exists()) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }) return } // 文件存在,则进行删除操作 let delRet = targetFile.delete() if (!delRet) { // 调用系统api 删除失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }) return } currentDispatcher.async(function (_) { let success : FileManagerSuccessResult = { errMsg: "unlink:ok" } // 删除成功 options.success?.(success) options.complete?.(success) }) }, null) } public readFileSync(filePath : string, encoding : string | null) : string { let msgPrefix = "readFileSync:fail " // 判断type 是否合法 let tempEncoding = encoding if (tempEncoding == null) { tempEncoding = "utf-8" } if (tempEncoding.toLowerCase() != 'base64' && tempEncoding.toLowerCase() != 'utf-8' && tempEncoding.toLowerCase() != 'ascii') { throw new UniError(UniErrorSubject, 1200002, msgPrefix + UniErrors.get(1200002)!) } let tempFilePath = UTSAndroid.convert2AbsFullPath(filePath) if (tempFilePath.startsWith("/android_asset/")) { let byteArray : ByteArray try { let assetName = tempFilePath.substring("/android_asset/".length) let assetStream = UTSAndroid.getAppContext()!.getResources().getAssets().open(assetName); let byteLen = assetStream.available(); byteArray = new ByteArray(byteLen) assetStream.read(byteArray); } catch (e : Exception) { throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)! + ":" + filePath) } if (tempEncoding.toLowerCase() == 'base64') { // base64 let base64Content = Base64.encodeToString(byteArray, Base64.NO_WRAP) return base64Content } else if (tempEncoding.toLowerCase() == "ascii") { // ascii let text = new String(byteArray, Charsets.US_ASCII) return text } else { // utf-8 兜底 let text = new String(byteArray, Charsets.UTF_8) return text } } else { let isSandyBox = isSandyBoxPath(tempFilePath, true) if (!isSandyBox) { return "1300013" } let targetFile = new File(tempFilePath) if (!targetFile.exists()) { throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)! + ":" + filePath); } if (targetFile.isDirectory()) { throw new UniError(UniErrorSubject, 1301003, msgPrefix + UniErrors.get(1301003)! + ":" + filePath); } /** * 文件超过100M,会超过应用内存 */ if (targetFile.length() > 100 * 1024 * 1024) { throw new UniError(UniErrorSubject, 1300202, msgPrefix + UniErrors.get(1300202)! + ":" + filePath); } if (tempEncoding.toLowerCase() == 'base64') { // base64 let byteArray = targetFile.readBytes() let base64Content = Base64.encodeToString(byteArray, Base64.NO_WRAP) return base64Content } else if (tempEncoding.toLowerCase() == "ascii") { // ascii let text = targetFile.readText(Charsets.US_ASCII) return text } else { // utf-8 兜底 let text = targetFile.readText(Charsets.UTF_8) return text } } } public readFile(options : ReadFileOptions) { // 判断type 是否合法 if (options.encoding.toLowerCase() != 'base64' && options.encoding.toLowerCase() != 'utf-8' && options.encoding.toLowerCase() != 'ascii') { let err = new UniError(UniErrorSubject, 1200002, UniErrors.get(1200002)!); options.fail?.(err) options.complete?.(err) return } let currentDispatcher = UTSAndroid.getDispatcher("main") /** * 执行真正的加载行为,为了避免阻塞分发到 io任务序列 */ UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) if (filePath.startsWith("/android_asset/")) { // 用户访问的是asset 路径,此时不是释放模式 let exceptionInfo : Exception | null = null let byteArray = new ByteArray(0) try { let assetName = filePath.substring("/android_asset/".length) let assetStream = UTSAndroid.getAppContext()!.getResources().getAssets().open(assetName); let byteLen = assetStream.available(); byteArray = new ByteArray(byteLen) assetStream.read(byteArray); } catch (e : Exception) { exceptionInfo = e } if (exceptionInfo != null) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + exceptionInfo.message); options.fail?.(err) options.complete?.(err) }) return } let ret : ReadFileSuccessResult = { data: "" } if (options.encoding.toLowerCase() == 'base64') { // base64 let base64Content = Base64.encodeToString(byteArray, Base64.NO_WRAP) ret.data = base64Content } else if (options.encoding.toLowerCase() == "ascii") { // ascii let text = new String(byteArray, Charsets.US_ASCII) ret.data = text } else { // utf-8 兜底 let text = new String(byteArray, Charsets.UTF_8) ret.data = text } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }) } else { let isSandyBox = isSandyBoxPath(filePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }) return } let targetFile = new File(filePath) if (!targetFile.exists()) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }) return } if (targetFile.isDirectory()) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1301003, UniErrors.get(1301003)!); options.fail?.(err) options.complete?.(err) }) return } /** * 文件超过100M,会超过应用内存 */ if (targetFile.length() > 100 * 1024 * 1024) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300202, UniErrors.get(1300202)!); options.fail?.(err) options.complete?.(err) }) return } let ret : ReadFileSuccessResult = { data: "" } if (options.encoding.toLowerCase() == 'base64') { // base64 let byteArray = targetFile.readBytes() let base64Content = Base64.encodeToString(byteArray, Base64.NO_WRAP) ret.data = base64Content } else if (options.encoding.toLowerCase() == "ascii") { // ascii let text = targetFile.readText(Charsets.US_ASCII) ret.data = text } else { // utf-8 兜底 let text = targetFile.readText(Charsets.UTF_8) ret.data = text } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }) } }, null) } public writeFileSync(filePath : string, data : string, encoding : string) : void { let msgPrefix = "writeFileSync:fail " let tempEncoding = encoding if (tempEncoding.toLowerCase() != 'base64' && tempEncoding.toLowerCase() != 'utf-8' && tempEncoding.toLowerCase() != 'ascii') { throw new UniError(UniErrorSubject, 1200002, msgPrefix + UniErrors.get(1200002)!) } // 判断type 是否合法 let tempFilePath = UTSAndroid.convert2AbsFullPath(filePath) let isSandyBox = isSandyBoxPath(tempFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let nextFile = new File(tempFilePath) if (nextFile.exists() && nextFile.isDirectory()) { throw new UniError(UniErrorSubject, 1301003, msgPrefix + UniErrors.get(1301003)!) } /** * 如果上一级目录不存在,创建之 */ if (!nextFile.parentFile!.exists()) { nextFile.parentFile!.mkdirs() } if (!nextFile.exists()) { nextFile.createNewFile() } // 写入文本,根据不同的编码内容写入不同的数据 if (tempEncoding.toLowerCase() == 'ascii') { // 与微信保持一致,以UTF-16 BE首字节为ascii let charArray = data.toCharArray() let charNum = charArray.size let byteArray = ByteArray(charNum) let index = 0; for (; index < charNum; index++) { let perByte = charArray[index.toInt()].toChar().code.toByte() byteArray.set(index.toInt(), perByte) } nextFile.writeBytes(byteArray) } else if (tempEncoding.toLowerCase() == 'base64') { // base64 nextFile.writeBytes(Base64.decode(data, Base64.NO_WRAP)) } else { // utf-8 兜底 nextFile.writeText(data, Charsets.UTF_8) } } public writeFile(options : WriteFileOptions) { if (options.encoding.toLowerCase() != 'base64' && options.encoding.toLowerCase() != 'utf-8' && options.encoding.toLowerCase() != 'ascii') { let err = new UniError(UniErrorSubject, 1200002, UniErrors.get(1200002)!); options.fail?.(err) options.complete?.(err) return } // 判断type 是否合法 let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) return } let nextFile = new File(filePath) if (nextFile.exists() && nextFile.isDirectory()) { // 出错了,目标文件已存在,并且是个目录 let err = new UniError(UniErrorSubject, 1301003, UniErrors.get(1301003)!); options.fail?.(err) options.complete?.(err) return } let currentDispatcher = UTSAndroid.getDispatcher() UTSAndroid.getDispatcher('io').async(function (_) { /** * 如果上一级目录不存在,创建之 */ if (!nextFile.parentFile!.exists()) { nextFile.parentFile!.mkdirs() } if (!nextFile.exists()) { nextFile.createNewFile() } // 写入文本,根据不同的编码内容写入不同的数据 if (options.encoding.toLowerCase() == 'ascii') { // 与微信保持一致,以UTF-16 BE首字节为ascii let charArray = options.data.toCharArray() let charNum = charArray.size let byteArray = ByteArray(charNum) let index = 0; for (; index < charNum; index++) { let perByte = charArray[index.toInt()].toChar().code.toByte() byteArray.set(index.toInt(), perByte) } nextFile.writeBytes(byteArray) } else if (options.encoding.toLowerCase() == 'base64') { // base64 nextFile.writeBytes(Base64.decode(options.data, Base64.NO_WRAP)) } else { // utf-8 兜底 nextFile.writeText(options.data, Charsets.UTF_8) } let ret : FileManagerSuccessResult = { errMsg: "writeFile:ok" } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }) }, null) } public appendFileSync(filePath : string, data : string, encoding : string) { let msgPrefix = "appendFileSync:fail " let tempEncoding = encoding if (tempEncoding.toLowerCase() != 'base64' && tempEncoding.toLowerCase() != 'utf-8' && tempEncoding.toLowerCase() != 'ascii') { throw new UniError(UniErrorSubject, 1200002, msgPrefix + UniErrors.get(1200002)!) } // 判断type 是否合法 let tempFilePath = UTSAndroid.convert2AbsFullPath(filePath) let isSandyBox = isSandyBoxPath(tempFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let nextFile = new File(tempFilePath) if (!nextFile.exists()) { throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } else if (nextFile.isDirectory()) { // 出错了,目标文件已存在,并且是个目录 throw new UniError(UniErrorSubject, 1301003, msgPrefix + UniErrors.get(1301003)!) } // 写入文本,根据不同的编码内容写入不同的数据 if (tempEncoding.toLowerCase() == 'ascii') { // 与微信保持一致,以UTF-16 BE首字节为ascii let charArray = data.toCharArray() let charNum = charArray.size let byteArray = ByteArray(charNum) let index = 0; for (; index < charNum; index++) { let perByte = charArray[index.toInt()].toChar().code.toByte() byteArray.set(index.toInt(), perByte) } nextFile.appendBytes(byteArray) } else if (tempEncoding.toLowerCase() == 'base64') { // base64 nextFile.appendBytes(Base64.decode(data, Base64.NO_WRAP)) } else { // utf-8 兜底 nextFile.appendText(data, Charsets.UTF_8) } } public appendFile(options : AppendFileOptions) { if (options.encoding.toLowerCase() != 'base64' && options.encoding.toLowerCase() != 'utf-8' && options.encoding.toLowerCase() != 'ascii') { let err = new UniError(UniErrorSubject, 1200002, UniErrors.get(1200002)!); options.fail?.(err) options.complete?.(err) return } // 判断type 是否合法 let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) return } let nextFile = new File(filePath) if (!nextFile.exists()) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)!); options.fail?.(err) options.complete?.(err) return } else if (nextFile.isDirectory()) { // 出错了,目标文件已存在,并且是个目录 let err = new UniError(UniErrorSubject, 1301003, UniErrors.get(1301003)!); options.fail?.(err) options.complete?.(err) return } let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { // 写入文本,根据不同的编码内容写入不同的数据 if (options.encoding.toLowerCase() == 'ascii') { // 与微信保持一致,以UTF-16 BE首字节为ascii let charArray = options.data.toCharArray() let charNum = charArray.size let byteArray = ByteArray(charNum) let index = 0; for (; index < charNum; index++) { let perByte = charArray[index.toInt()].toChar().code.toByte() byteArray.set(index.toInt(), perByte) } nextFile.appendBytes(byteArray) } else if (options.encoding.toLowerCase() == 'base64') { // base64 nextFile.appendBytes(Base64.decode(options.data, Base64.NO_WRAP)) } else { // utf-8 兜底 nextFile.appendText(options.data, Charsets.UTF_8) } let ret : FileManagerSuccessResult = { errMsg: "appendFile:ok" } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }, null) }, null) } public open(options : OpenFileOptions) { let optFlag = options.flag.toLowerCase() if (optFlag != 'a' && optFlag != 'ax' && optFlag != 'a+' && optFlag != 'ax+' && optFlag != "r" && optFlag != 'r+' && optFlag != 'w' && optFlag != 'wx' && optFlag != 'w+' && optFlag != 'wx' && optFlag != 'wx+') { let err = new UniError(UniErrorSubject, 1302003, UniErrors.get(1302003)!); options.fail?.(err) options.complete?.(err) return } let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) return } this.fileDesUtil.open(options, new File(filePath)) } public openSync(options : OpenFileSyncOptions) : string { let msgPrefix = "openSync:fail " let optFlag = options.flag.toLowerCase() if (optFlag != 'a' && optFlag != 'ax' && optFlag != 'a+' && optFlag != 'ax+' && optFlag != "r" && optFlag != 'r+' && optFlag != 'w' && optFlag != 'wx' && optFlag != 'w+' && optFlag != 'wx' && optFlag != 'wx+') { throw new UniError(UniErrorSubject, 1302003, msgPrefix + UniErrors.get(1302003)!) } let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let isSandyBox = isSandyBoxPath(filePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } return this.fileDesUtil.openSync(options, new File(filePath)) } public saveFile(options : SaveFileOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { // 检查来源文件 let tempFilePath = UTSAndroid.convert2AbsFullPath(options.tempFilePath) let isSandyBox = isSandyBoxPath(tempFilePath, true) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.tempFilePath); options.fail?.(err) options.complete?.(err) }, null) return } let targetFile = new File(tempFilePath) if (!targetFile.exists()) { /** * 文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.tempFilePath); options.fail?.(err) options.complete?.(err) }, null) return } if (options.filePath == null) { options.filePath = uni.env.USER_DATA_PATH } // 检查目标文件 let newFilePath = UTSAndroid.convert2AbsFullPath(options.filePath! + targetFile.getName()) isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }, null) return } let newFile = new File(newFilePath) console.log(newFile.getPath()) if (newFile.getParentFile() != null && !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.filePath); options.fail?.(err) options.complete?.(err) }, null) return } let copyRetFile = targetFile.copyTo(newFile, true) if (!copyRetFile.exists()) { // 调用系统api 失败 currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)!); options.fail?.(err) options.complete?.(err) }, null) return } targetFile.delete() let ret : SaveFileSuccessResult = { savedFilePath: newFile.getPath() } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }, null) }, null) } public saveFileSync(tempFilePath : string, filePath : string | null) : string { let msgPrefix = "saveFileSync:fail " // 检查来源文件 let tfPath = UTSAndroid.convert2AbsFullPath(tempFilePath) let isSandyBox = isSandyBoxPath(tfPath, true) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let targetFile = new File(tfPath) if (!targetFile.exists()) { /** * 文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } let fp = filePath if (fp == null) { fp = uni.env.USER_DATA_PATH } // 检查目标文件 let newFilePath = UTSAndroid.convert2AbsFullPath(fp + targetFile.getName()) isSandyBox = isSandyBoxPath(newFilePath, false) if (!isSandyBox) { throw new UniError(UniErrorSubject, 1300013, msgPrefix + UniErrors.get(1300013)!) } let newFile = new File(newFilePath) console.log(newFile.getPath()) if (newFile.getParentFile() != null && !newFile.getParentFile()!.exists()) { /** * 父文件不存在 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } let copyRetFile = targetFile.copyTo(newFile, true) if (!copyRetFile.exists()) { // 调用系统api 失败 throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } targetFile.delete() return newFilePath } public unzip(options : UnzipFileOptions) { let msgPrefix = "unzip:fail " // 检查来源文件 let zipFilePath = UTSAndroid.convert2AbsFullPath(options.zipFilePath) let isSandyBox = isSandyBoxPath(zipFilePath, true) let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.zipFilePath); options.fail?.(err) options.complete?.(err) }, null) return } let zipFile = new File(zipFilePath) if (!zipFile.exists()) { /** * 文件不存在 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.zipFilePath); options.fail?.(err) options.complete?.(err) }, null) return } let targetPath = UTSAndroid.convert2AbsFullPath(options.targetPath) isSandyBox = isSandyBoxPath(targetPath, true) let targetFile = new File(targetPath) if (!isSandyBox) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300013, UniErrors.get(1300013)! + ":" + options.zipFilePath); options.fail?.(err) options.complete?.(err) }, null) return } if (!targetFile.exists() || !targetFile.isDirectory()) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + options.zipFilePath); options.fail?.(err) options.complete?.(err) }, null) return } try { let is = new FileInputStream(zipFile); let zis = new ZipInputStream(new BufferedInputStream(is)); console.log(zipFile.getPath()) let buffer = new ByteArray(1024) let count : number = 0; let ze = zis.getNextEntry() while (ze != null) { // ze 是每个条目,我们需要获取对应的文件名 let filename = ze.getName(); // 若是文件夹,直接创建 if (ze.isDirectory()) { let fmd = new File(targetPath + "/" + filename); fmd.mkdirs(); ze = zis.getNextEntry() continue; } if (filename.startsWith("__MACOSX")) {//mac os上压缩的zip会产生该文件夹 ze = zis.getNextEntry() continue; } // // 否则我们将文件提取出来 let fout = new FileOutputStream(targetPath + "/" + filename); console.log(targetPath + "/" + filename) // 将压缩文件内容写入到这个文件中 let count = zis.read(buffer) while (count != -1) { fout.write(buffer, 0, count); count = zis.read(buffer) } fout.close(); zis.closeEntry(); ze = zis.getNextEntry() } zis.close(); let ret : FileManagerSuccessResult = { errMsg: "unzip:ok" } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }, null) } catch (e : Exception) { console.log(e.message) currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + options.zipFilePath); options.fail?.(err) options.complete?.(err) }, null) return } }, null) } public getSavedFileList(options : GetSavedFileListOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(uni.env.USER_DATA_PATH) let targetFile = new File(filePath) if (!targetFile.exists() || !targetFile.isDirectory()) { /** * 文件不存在,或者不是文件夹,异常 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + filePath); options.fail?.(err) options.complete?.(err) }, null) return } let res : Array = [] targetFile.walk() .onEnter(function (file : File) : boolean { if (file.isDirectory()) { return true } return false }) .iterator() .forEach(function (file : File) { if (!file.isDirectory()) { res.add(file.getPath()) } }) let success : GetSavedFileListResult = { fileList: UTSArray.fromNative(res) } currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }, null) }, null) } public truncate(options : TruncateFileOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let targetFile = new File(filePath) if (!targetFile.exists() || targetFile.isDirectory()) { /** * 文件不存在,或者是文件夹,异常 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + filePath); options.fail?.(err) options.complete?.(err) }, null) return } let content = targetFile.readText() if (content.length > options.length) { let truncatedContent = content.substring(0, options.length) targetFile.writeText(truncatedContent) } let success : FileManagerSuccessResult = { errMsg: "truncateFile:ok" } currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }, null) }, null) } truncateSync(filePath : string, length ?: number) { let msgPrefix = 'truncateSync:fail ' let tempLength = length if (tempLength == null) { tempLength = 0 } let tempFilePath = UTSAndroid.convert2AbsFullPath(filePath) let targetFile = new File(tempFilePath) if (!targetFile.exists() || targetFile.isDirectory()) { /** * 文件不存在,或者是文件夹,异常 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } let content = targetFile.readText() if (content.length > tempLength) { let truncatedContent = content.substring(0, tempLength) targetFile.writeText(truncatedContent) } } readCompressedFile(options : ReadCompressedFileOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let targetFile = new File(filePath) if (!targetFile.exists() || targetFile.isDirectory()) { /** * 文件不存在,或者是文件夹,异常 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + filePath); options.fail?.(err) options.complete?.(err) }, null) return } if (options.compressionAlgorithm != 'br') { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1301111, UniErrors.get(1301111)! + ":" + filePath); options.fail?.(err) options.complete?.(err) }, null) return } let success : ReadCompressedFileResult = { data: "" } try { let brInput = new BrotliInputStream(new FileInputStream(targetFile)) success.data = new String(brInput.readBytes()) brInput.close() } catch (e : Exception) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300201, UniErrors.get(1300201)! + ":" + filePath); options.fail?.(err) options.complete?.(err) }, null) return } currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }, null) }, null) } readCompressedFileSync(filePath : string, compressionAlgorithm : string) : string { let msgPrefix = "readCompressedFileSync:fail " let tempFilePath = UTSAndroid.convert2AbsFullPath(filePath) let targetFile = new File(tempFilePath) if (!targetFile.exists() || targetFile.isDirectory()) { /** * 文件不存在,或者是文件夹,异常 */ throw new UniError(UniErrorSubject, 1300002, msgPrefix + UniErrors.get(1300002)!) } if (compressionAlgorithm != 'br') { throw new UniError(UniErrorSubject, 1301111, msgPrefix + UniErrors.get(1301111)!) } let data : string try { let brInput = new BrotliInputStream(new FileInputStream(targetFile)) data = new String(brInput.readBytes()) brInput.close() } catch (e : Exception) { throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } return data } removeSavedFile(options : RemoveSavedFileOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let filePath = UTSAndroid.convert2AbsFullPath(options.filePath) let targetFile = new File(filePath) if (!targetFile.exists() || targetFile.isDirectory()) { /** * 文件不存在,或者是文件夹,异常 */ currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300002, UniErrors.get(1300002)! + ":" + filePath); options.fail?.(err) options.complete?.(err) }, null) return } targetFile.delete() currentDispatcher.async(function (_) { let success : FileManagerSuccessResult = { errMsg: "removeSavedFile:ok" } options.success?.(success) options.complete?.(success) }, null) }, null) } public write(options : WriteOptions) { console.log(JSON.stringify(options)) if (options.encoding.toLowerCase() != 'base64' && options.encoding.toLowerCase() != 'utf-8' && options.encoding.toLowerCase() != 'ascii') { let err = new UniError(UniErrorSubject, 1200002, UniErrors.get(1200002)!); options.fail?.(err) options.complete?.(err) return } let currentDispatcher = UTSAndroid.getDispatcher() UTSAndroid.getDispatcher('io').async(function (_) { let fd = ParcelFileDescriptor.fromFd(options.fd.toInt()) if (fd == null) { let err = new UniError(UniErrorSubject, 1300009, UniErrors.get(1300009)!); options.fail?.(err) options.complete?.(err) return } let outStream = new FileOutputStream(fd.getFileDescriptor()) let fileChannel = outStream.getChannel() //创建ByteBuffer并写入数据 let buffer = ByteBuffer.allocate(64) buffer.clear() // 写入文本,根据不同的编码内容写入不同的数据 if (options.encoding.toLowerCase() == 'ascii') { // 与微信保持一致,以UTF-16 BE首字节为ascii let charArray = options.data.toCharArray() let charNum = charArray.size let byteArray = ByteArray(charNum) let index = 0; for (; index < charNum; index++) { let perByte = charArray[index.toInt()].toChar().code.toByte() byteArray.set(index.toInt(), perByte) } buffer.put(byteArray) } else if (options.encoding.toLowerCase() == 'base64') { // base64 buffer.put(Base64.decode(options.data, Base64.NO_WRAP)) } else { // utf-8 兜底 buffer.put(options.data.toByteArray()) } buffer.flip() while (buffer.hasRemaining()) { fileChannel.write(buffer, 0) } let ret : WriteResult = { bytesWritten: options.data.length } currentDispatcher.async(function (_) { options.success?.(ret) options.complete?.(ret) }) }, null) } public writeSync(options : WriteSyncOptions) : WriteResult { let msgPrefix = "writeSync:fail " if (options.encoding.toLowerCase() != 'base64' && options.encoding.toLowerCase() != 'utf-8' && options.encoding.toLowerCase() != 'ascii') { throw new UniError(UniErrorSubject, 1200002, msgPrefix + UniErrors.get(1200002)!) } let fd = ParcelFileDescriptor.fromFd(options.fd.toInt()) if (fd == null) { throw new UniError(UniErrorSubject, 1300009, msgPrefix + UniErrors.get(1300009)!) } try { let outStream = new FileOutputStream(fd.getFileDescriptor()) let fileChannel = outStream.getChannel() //创建ByteBuffer并写入数据 let buffer = ByteBuffer.allocate(64) buffer.clear() // 写入文本,根据不同的编码内容写入不同的数据 if (options.encoding.toLowerCase() == 'ascii') { // 与微信保持一致,以UTF-16 BE首字节为ascii let charArray = options.data.toCharArray() let charNum = charArray.size let byteArray = ByteArray(charNum) let index = 0; for (; index < charNum; index++) { let perByte = charArray[index.toInt()].toChar().code.toByte() byteArray.set(index.toInt(), perByte) } buffer.put(byteArray) } else if (options.encoding.toLowerCase() == 'base64') { // base64 buffer.put(Base64.decode(options.data, Base64.NO_WRAP)) } else { // utf-8 兜底 buffer.put(options.data.toByteArray()) } buffer.flip() while (buffer.hasRemaining()) { fileChannel.write(buffer, 0) } } catch (e) { throw new UniError(UniErrorSubject, 1300201, msgPrefix + UniErrors.get(1300201)!) } let ret : WriteResult = { bytesWritten: options.data.length } return ret } public close(options : CloseOptions) { let fd = ParcelFileDescriptor.fromFd(options.fd.toInt()) UTSAndroid.getDispatcher('io').async(function (_) { try { fd.close() let success : FileManagerSuccessResult = { errMsg: "close:ok", } if (this.fileDesUtil.openMap.has(options.fd)) { this.fileDesUtil.openMap.delete(options.fd) } options.success?.(success) options.complete?.(success) } catch (e) { let err = new UniError(UniErrorSubject, 1300009, UniErrors.get(1300009)!); options.fail?.(err) options.complete?.(err) } }) } public closeSync(options : CloseSyncOptions) { let msgPrefix = "closeSync:fail " let fd = ParcelFileDescriptor.fromFd(options.fd.toInt()) try { fd.close() if (this.fileDesUtil.openMap.has(options.fd)) { this.fileDesUtil.openMap.delete(options.fd) } } catch (e) { throw new UniError(UniErrorSubject, 1300009, msgPrefix + UniErrors.get(1300009)!) } } public fstat(options : FStatOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { currentDispatcher.async(function (_) { if (!this.fileDesUtil.openMap.has(options.fd)) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300009, UniErrors.get(1300009)! + ":" + options.fd); options.fail?.(err) options.complete?.(err) }, null) return } let success : FStatSuccessResult = { stats: wrapStats(this.fileDesUtil.openMap.get(options.fd)!) } options.success?.(success) options.complete?.(success) }, null) }, null) } public fstatSync(options : FStatSyncOptions) : Stats { let msgPrefix = "ftruncateSync:fail " if (!this.fileDesUtil.openMap.has(options.fd)) { throw new UniError(UniErrorSubject, 1300009, msgPrefix + UniErrors.get(1300009)!) } return wrapStats(this.fileDesUtil.openMap.get(options.fd)!) } public ftruncate(options : FTruncateFileOptions) { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { if (!this.fileDesUtil.openMap.has(options.fd)) { currentDispatcher.async(function (_) { let err = new UniError(UniErrorSubject, 1300009, UniErrors.get(1300009)! + ":" + options.fd); options.fail?.(err) options.complete?.(err) }, null) return } let targetFile = this.fileDesUtil.openMap.get(options.fd) let content = targetFile!.readText() if (content.length > options.length) { let truncatedContent = content.substring(0, options.length) targetFile.writeText(truncatedContent) } let success : FileManagerSuccessResult = { errMsg: "ftruncate:ok" } currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }, null) }, null) } public ftruncateSync(options : FTruncateFileSyncOptions) { let msgPrefix = "ftruncateSync:fail " if (!this.fileDesUtil.openMap.has(options.fd)) { throw new UniError(UniErrorSubject, 1300009, msgPrefix + UniErrors.get(1300009)!) } let targetFile = this.fileDesUtil.openMap.get(options.fd) let content = targetFile!.readText() if (content.length > options.length) { let truncatedContent = content.substring(0, options.length) targetFile.writeText(truncatedContent) } } public readZipEntry(options : ReadZipEntryOptions) { let targetPath = uni.env.CACHE_PATH + "/" + Base64.encodeToString(options.filePath.toByteArray(), Base64.NO_WRAP) targetPath = UTSAndroid.convert2AbsFullPath(targetPath) console.log("readZipEntry", targetPath) let file : File = new File(targetPath) if (!file.exists()) { file.mkdirs() } let target = this let zipOptions : UnzipFileOptions = { zipFilePath: options.filePath, targetPath: targetPath, success: (_) => { let currentDispatcher = UTSAndroid.getDispatcher("main") UTSAndroid.getDispatcher('io').async(function (_) { let targetFile = new File(targetPath) let resultMap : Map = new Map() let filterEntries = options.entries filterEntries?.forEach((item) => { let fileItem = new File(targetPath + "/" + item.path) console.log("readZipEntry", file.getPath()) if (!fileItem.exists() || fileItem.isDirectory()) { let zipFileItem : ZipFileItem = { errMsg: 'no such file' } resultMap.set(item.path, zipFileItem) } }) targetFile.walk() .onEnter(function (file : File) : boolean { if (file.isDirectory()) { return true } return false }) .iterator() .forEach(function (file : File) { if (options.entries == null) { if (!file.isDirectory()) { let data = target.readFileSync(file.getPath(), options.encoding) let zipFileItem : ZipFileItem = { data: data, errMsg: 'readZipEntry:ok' } resultMap.set(file.getPath().substring(targetPath.length + 1), zipFileItem) } } else { if (!file.isDirectory()) { filterEntries?.forEach((item) => { let entryPath = targetPath + "/" + item.path console.log("readZipEntry", file.getPath()) if (entryPath == file.getPath()) { let data = target.readFileSync(file.getPath(), item.encoding) let zipFileItem : ZipFileItem = { data: data, errMsg: 'readZipEntry:ok' } resultMap.set(item.path, zipFileItem) } }) } } }) let success : EntriesResult = { result: resultMap } currentDispatcher.async(function (_) { options.success?.(success) options.complete?.(success) }, null) targetFile.delete() }) }, fail: (res : UniError) => { let err = new UniError(UniErrorSubject, res.errCode, res.errMsg); options.fail?.(err) options.complete?.(err) } } this.unzip(zipOptions) } } export const getFileSystemManager : GetFileSystemManager = function () : FileSystemManager { return AndroidFileSystemManager.getManager() }; /** * 判断传入的路径是否是沙盒路径,如果不是则不能继续操作 */ function isSandyBoxPath(inputPath : string, onlyRead : boolean) : boolean { //处理非沙盒目录时 需要校验一下MANAGE_EXTERNAL_STORAGE权限 如果授权则可任意操作 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Environment.isExternalStorageManager()) { console.log('Environment.isExternalStorageManager()') return true } } /** * 第一条规则,判断是否操作的是应用资源目录。开发者具备该目录下读取的权限操作 */ let appResRoot = UTSAndroid.convert2AbsFullPath(uni.env.APP_RESOURCE_PATH) if (inputPath.startsWith(appResRoot)) { // 路径是应用资源目录 if (onlyRead) { // 并且是读取操作,返回 return true } else { // 不是读取 return false } } /** * 第二条规则,是否属于应用根目录 SANDBOX_PATH */ let sandyBoxRoot = UTSAndroid.convert2AbsFullPath(uni.env.SANDBOX_PATH) if (inputPath.startsWith(sandyBoxRoot)) { // 是否是应用根目录 return true } /** * 第三条规则,是否属于应用内置根目录 ANDROID_INTERNAL_SANDBOX_PATH */ let innerSandyBoxRoot = UTSAndroid.convert2AbsFullPath(uni.env.ANDROID_INTERNAL_SANDBOX_PATH) if (inputPath.startsWith(innerSandyBoxRoot)) { // 是否是应用根目录 return true } return false } function wrapStats(sourceFile : File) : Stats { let stats = new AndroidStats() stats.mIsFile = sourceFile.isFile() stats.lastModifiedTime = sourceFile.lastModified() stats.mode = getFileMode(sourceFile) if (sourceFile.isFile()) { stats.size = sourceFile.length() } return stats } function getFileMode(sourceFile : File) : number { let res = "0" if (sourceFile.isFile()) { res += "10" } else if (sourceFile.isDirectory()) { res += "04" } //let file=new File("") // S_IRUSR (00400):所有者读权限。 // S_IWUSR (00200):所有者写权限。 // S_IXUSR (00100):所有者执行权限。 //S_IRWXU (00700):所有者的权限。100644 let permission = 7 if (sourceFile.canRead() && sourceFile.canWrite() && sourceFile.canExecute()) { permission = 7 } else { if (!sourceFile.canRead()) { permission = permission - 4 } if (!sourceFile.canWrite()) { permission = permission - 2 } if (!sourceFile.canExecute()) { permission = permission - 1 } } res += "0" + permission + "00" return Integer.parseInt(res, 8) }