文件系统 - Files

# Files files模块提供了一些常见的文件处理,包括文件读写、移动、复制、删掉等。 >i 一次性的文件读写可以直接使用files.read(), files.write(), files.append()等方便的函数,但如果需要频繁读写或随机读写,则使用open()函数打开一个文件对象来操作文件,并在操作完毕后调用close()函数关闭文件。 ## files.isFile(path) - path {string} 路径 返回 {boolean} 返回路径path是否是文件。 ```js log(files.isDir("/sdcard/文件夹/")); //返回false log(files.isDir("/sdcard/文件.txt")); //返回true ``` ## files.isDir(path) - path {string} 路径 返回 {boolean} 返回路径path是否是文件夹。 ```js log(files.isDir("/sdcard/文件夹/")); //返回true log(files.isDir("/sdcard/文件.txt")); //返回false ``` ## files.isEmptyDir(path) - path {string} 路径 返回 {boolean} 返回文件夹path是否为空文件夹。如果该路径并非文件夹,则直接返回false。 ## files.join(parent, child) - parent {string} 父目录路径 - child {string} 子路径 返回 {string} 连接两个路径并返回,例如files.join("/sdcard/", "1.txt")返回"/sdcard/1.txt"。 ## files.create(path) - path {string} 路径 返回 {boolean} 创建一个文件或文件夹并返回是否创建成功。如果文件已经存在,则直接返回false。 ```js files.create("/sdcard/新文件夹/"); ``` ## files.createWithDirs(path) - path {string} 路径 返回 {boolean} 创建一个文件或文件夹并返回是否创建成功。如果文件所在文件夹不存在,则先创建他所在的一系列文件夹。如果文件已经存在,则直接返回false。 ```js files.createWithDirs("/sdcard/新文件夹/新文件夹/新文件夹/1.txt"); ``` ## files.exists(path) - path {string} 路径 返回 {boolean} 返回在路径path处的文件是否存在。 ## files.ensureDir(path) - path {string} 路径 确保路径path所在的文件夹存在。如果该路径所在文件夹不存在,则创建该文件夹。 例如对于路径"/sdcard/Download/ABC/1.txt",如果/Download/文件夹不存在,则会先创建Download,再创建ABC文件夹。 ## files.read(path[, encoding = "utf-8"]) - path {string} 路径 - encoding {string} 字符编码,可选,默认为utf-8 返回 {string} 读取文本文件path的所有内容并返回。如果文件不存在,则抛出FileNotFoundException。 ```js log(files.read("/sdcard/1.txt")); ``` ## files.readBytes(path) - path {string} 路径 返回 {byte[]} 读取文件path的所有内容并返回一个字节数组。如果文件不存在,则抛出FileNotFoundException。 注意,该数组是Java的数组,不具有JavaScript数组的forEach, slice等函数。 一个以16进制形式打印文件的例子如下: ```js var data = files.readBytes("/sdcard/1.png"); var sb = new java.lang.StringBuilder(); for(var i = 0; i < data.length; i++){ sb.append(data[i].toString(16)); } log(sb.toString()); ``` ## files.write(path, text[, encoding = "utf-8"]) - path {string} 路径 - text {string} 要写入的文本内容 - encoding {string} 字符编码 把text写入到文件path中。如果文件存在则覆盖,不存在则创建。 ```js var text = "文件内容"; //写入文件 files.write("/sdcard/1.txt", text); //用其他应用查看文件 app.viewFile("/sdcard/1.txt"); ``` ## files.writeBytes(path, bytes) - path {string} 路径 - bytes {byte[]} 字节数组,要写入的二进制数据 把bytes写入到文件path中。如果文件存在则覆盖,不存在则创建。 ## files.append(path, text[, encoding = 'utf-8']) - path {string} 路径 - text {string} 要写入的文本内容 - encoding {string} 字符编码 把text追加到文件path的末尾。如果文件不存在则创建。 ```js var text = "追加的文件内容"; files.append("/sdcard/1.txt", text); files.append("/sdcard/1.txt", text); //用其他应用查看文件 app.viewFile("/sdcard/1.txt"); ``` ## files.appendBytes(path, text[, encoding = 'utf-8']) - path {string} 路径 - bytes {byte[]} 字节数组,要写入的二进制数据 把bytes追加到文件path的末尾。如果文件不存在则创建。 ## files.copy(fromPath, toPath) - from- path {string} 要复制的原文件路径 - to- path {string} 复制到的文件路径 返回 {boolean} 复制文件,返回是否复制成功。例如files.copy("/sdcard/1.txt", "/sdcard/Download/1.txt")。 ## files.move(fromPath, toPath) - from- path {string} 要移动的原文件路径 - to- path {string} 移动到的文件路径 返回 {boolean} 移动文件,返回是否移动成功。例如files.move("/sdcard/1.txt", "/sdcard/Download/1.txt")会把1.txt文件从sd卡根目录移动到Download文件夹。 ## files.rename(path, newName) - path {string} 要重命名的原文件路径 - newName {string} 要重命名的新文件名 返回 {boolean} 重命名文件,并返回是否重命名成功。例如files.rename("/sdcard/1.txt", "2.txt")。 ## files.renameWithoutExtension(path, newName) - path {string} 要重命名的原文件路径 - newName {string} 要重命名的新文件名 返回 {boolean} 重命名文件,不包含拓展名,并返回是否重命名成功。例如files.rename("/sdcard/1.txt", "2")会把"1.txt"重命名为"2.txt"。 ## files.getName(path) - path {string} 路径 返回 {string} 返回文件的文件名。例如files.getName("/sdcard/1.txt")返回"1.txt"。 ## files.getNameWithoutExtension(path) - path {string} 路径 返回 {string} 返回不含拓展名的文件的文件名。例如files.getName("/sdcard/1.txt")返回"1"。 ## files.getExtension(path) - path {string} 路径 返回 {string} 返回文件的拓展名。例如files.getExtension("/sdcard/1.txt")返回"txt"。 ## files.remove(path) - path {string} 路径 返回 {boolean} 删除文件或空文件夹,返回是否删除成功。 ## files.removeDir(path) - path {string} 路径 返回 {boolean} 删除文件夹,如果文件夹不为空,则删除该文件夹的所有内容再删除该文件夹,返回是否全部删除成功。 ## files.getSdcardPath() 返回 {string} 返回SD卡路径。所谓SD卡,即外部存储器。 ## files.cwd() 返回 {string} 返回脚本的"当前工作文件夹路径"。该路径指的是,如果脚本本身为脚本文件,则返回这个脚本文件所在目录;否则返回null获取其他设定路径。 例如,对于脚本文件"/sdcard/脚本/1.js"运行files.cwd()返回"/sdcard/脚本/"。 ## files.path(relativePath) - relative- path {string} 相对路径 返回 {string} 返回相对路径对应的绝对路径。例如files.path("./1.png"),如果运行这个语句的脚本位于文件夹"/sdcard/脚本/"中,则返回"/sdcard/脚本/1.png"。 ## files.listDir(path[, filter]) - path {string} 路径 - filter {Function} 过滤函数,可选。接收一个string参数(文件名),返回一个boolean值。 列出文件夹path下的满足条件的文件和文件夹的名称的数组。如果不加filter参数,则返回所有文件和文件夹。 列出sdcard目录下所有文件和文件夹为: ```js var arr = files.listDir("/sdcard/"); log(arr); ``` 列出脚本目录下所有js脚本文件为: ```js var dir = "/sdcard/脚本/"; var jsFiles = files.listDir(dir, function(name){ return name.endsWith(".js") && files.isFile(files.join(dir, name)); }); log(jsFiles); ``` ## open(path[, mode = "r", encoding = "utf-8", bufferSize = 8192]) - path {string} 文件路径,例如"/sdcard/1.txt"。 - mode {string} 文件打开模式,包括: > "r": 只读文本模式。该模式下只能对文件执行文本读取操作。 "w": 只写文本模式。该模式下只能对文件执行文本覆盖写入操作。 "a": 附加文本模式。该模式下将会把写入的文本附加到文件末尾。 "rw": 随机读写文本模式。该模式下将会把写入的文本附加到文件末尾。 目前暂不支持二进制模式,随机读写模式。 - encoding {string} 字符编码。 - bufferSize {number} 文件读写的缓冲区大小。 打开一个文件。根据打开模式返回不同的文件对象。包括: > "r": 返回一个ReadableTextFile对象。 "w", "a": 返回一个WritableTextFile对象。 对于"w"模式,如果文件并不存在,则会创建一个,已存在则会清空该文件内容;其他模式文件不存在会抛出FileNotFoundException。 # ReadableTextFile 可读文件对象。 ## ReadableTextFile.read() 返回该文件剩余的所有内容的字符串。 ## ReadableTextFile.read(maxCount) - maxCount {Number} 最大读取的字符数量 读取该文件接下来最长为maxCount的字符串并返回。即使文件剩余内容不足maxCount也不会出错。 ## ReadableTextFile.readline() 读取一行并返回(不包含换行符)。 ## ReadableTextFile.readlines() 读取剩余的所有行,并返回它们按顺序组成的字符串数组。 ## close() 关闭该文件。 打开一个文件不再使用时务必关闭 # PWritableTextFile 可写文件对象。 ## PWritableTextFile.write(text) - text {string} 文本 把文本内容text写入到文件中。 ## PWritableTextFile.writeline(line) - text {string} 文本 把文本line写入到文件中并写入一个换行符。 ## PWritableTextFile.writelines(lines) - lines {Array} 字符串数组 把很多行写入到文件中.... ## PWritableTextFile.flush() 把缓冲区内容输出到文件中。 ## PWritableTextFile.close() 关闭文件。同时会被缓冲区内容输出到文件。 >d **打开一个文件写入后,不再使用时务必关闭,否则文件可能会丢失** # 示例 ## 读取文本文件 ```js //文件路径 var path = "/sdcard/1.txt"; //打开文件 var file = open(path); //读取文件的所有内容 var text = file.read(); //打印到控制台 print(text); //关闭文件 file.close(); console.show(); ``` ## 读写文本文件 ```js //以写入模式打开SD卡根目录文件1.txt var file = open("/sdcard/1.txt", "w") //写入aaaa file.write("aaaa"); //写入bbbbb后换行 file.writeline("bbbbb"); //写入ccc与ddd两行 file.writelines(["ccc", "ddd"]); //关闭文件 file.close(); //以附加模式打开文件 file = open("/sdcard/1.txt", "a"); //附加一行"啦啦啦啦" file.writeline("啦啦啦啦"); //附加一行"哈哈哈哈" file.writeline("哈哈哈哈"); //附加两行ccc, ddd file.writelines(["ccc", "ddd"]); //输出缓冲区 file.flush(); //关闭文件 file.close(); //以读取模式打开文件 file = open("/sdcard/test.txt", "r") //读取一行并打印 print(file.readline()); //读取剩余所有行并打印 for each(line in file.readlines()){ print(line) } file.close() //显示控制台 console.show() ``` ## 删除所有空文件夹 ```js if(confirm("该操作会删除SD卡目录及其子目录下所有空文件夹,是否继续?")){ toast("请点击右上角打开日志"); deleteAllEmptyDirs(files.getSdcardPath()); toast("全部完成!"); } function deleteAllEmptyDirs(dir){ var list = files.listDir(dir); var len = list.length; if(len == 0){ log("删除目录 " + dir + " " + (files.remove(dir) ? "成功" : "失败")); return; } for(let i = 0; i < len; i++){ var child = files.join(dir, list[i]); if(files.isDir(child)){ deleteAllEmptyDirs(child); } } } ``` ## 文件编码转换 ```js //以UTF-8编码打开SD卡上的1.txt文件 var f = open("/sdcard/1.txt", "r", "utf-8"); //读取文件所有内容 var text = f.read(); //关闭文件 f.close(); //以gbk编码打开SD卡上的2.txt文件 var out = open("/sdcard/2.txt", "w", "gbk"); //写入内容 out.write(text); //关闭文件 out.close(); ``` ## 文件编码转换(高级) ```js convert("/sdcard/1.txt", "utf-8", "/sdcard/2.txt", "gbk"); /** * fromFile: 源文件路径 * fromEncoding: 源文件编码 * toFile: 输出文件路径 * toEncoding: 输出文件编码 */ function convert(fromFile, fromEncoding, toFile, toEncoding){ fromFile = open(fromFile, "r", fromEncoding); toFile = open(toFile, "w", toEncoding); while(true){ var line = fromFile.readline(); if(!line) break; toFile.writeline(line); } } ``` ## 写入文本文件 ```js //文件路径 var path = "/sdcard/1.txt"; //要写入的文件内容 var text = "Hello, AutoJs"; //以写入模式打开文件 var file = open(path, "w"); //写入文件 file.write(text); //关闭文件 file.close(); ``` ## 生成二维码 ```js //生成二维码 //from:https://thbelief.coding.me/2019/04/18/Auto-js-Script开发-十一/ //网络请求图片然后保存到本地 //这里用的是type1,返回的是base64encode编码的字符串,type2返回的就是图片png格式 threads.start(function () { var url = "http://apis.juhe.cn/qrcode/api?key=684e3d257f6034ebdfd80a2bbeddeb18&type=2&fgcolor=" + ui.backgroundColor.text() + "&w=" + ui.size.text() + "&m=" + ui.marginSize.text() + "&text=" + ui.textContent.text(); var img = images.load(url); if (img != null) { toast("网络请求成功"); //提示一下是不是要生成? //在根目录下创建一个文件夹“THBELIEFScript二维码” files.create("/sdcard/THBELIEFScript二维码/"); images.save(img, "/sdcard/THBELIEFScript二维码/" + ui.textContent.text() + ".png", "png", 100); toast("该二维码图片保存在" + "/sdcard/THBELIEFScript二维码/" + ui.textContent.text() + ".png"); log("该二维码图片保存在" + "/sdcard/THBELIEFScript二维码/" + ui.textContent.text() + ".png"); } else {//网络请求失败 toast("网络请求失败!"); }; }); ``` > 以下非官方例子 ## QQ登录取号删号 ```js launchApp("QQ"); if (text("允许").findOne(5000)) { text("允许").findOne(5000).click() sleep(500) text("允许").findOne(5000).click() } className("android.widget.Button").text("登录").waitFor(); if (className("android.widget.Button").text("登录").findOne(5000)) { className("android.widget.Button").text("登录").findOne(5000).click() log("开始分割账号") toast("开始分割账号") } file = open("/sdcard/脚本/腾讯账号.txt", "r") //读取一行并打印 var 内容 = file.readline(); toast(内容) file.close(); var 登陆分割后的数据 = 内容.split("----"); log(登陆分割后的数据); var 账号 = 登陆分割后的数据[0]; log(账号); var 密码 = 登陆分割后的数据[1]; log(密码) setText([0], 账号)//把“你好”输入到下标为1的输入框里 setText([1], 密码)//把“你好”输入到下标为1的输入框里 className("android.widget.ImageView").desc("登 录").findOne(5000).click() toastLog(read_delete());//删除账号 function read_delete() { //删除第一行 var path = "/sdcard/脚本/腾讯账号.txt";//txt文本路径 var reg = /^\s+|s+$/g; //匹配无效空白行 var txt = files.read(path).replace(reg, "").split("\n"); let ret_text = txt[0]; log(ret_text.length); if (txt != "") { txt.splice(0, 1); //删除 files.write(path, txt.join("\n")); if (ret_text.length > 0) { return ret_text.trim(); }; } else { return "没有号了" }; file.close(); }; ``` ## zip文件压缩 ```js // zip压缩("/storage/emulated/0/脚本/") // zip解压('/storage/emulated/0/脚本/zip4j_1.3.2.jar', "/storage/emulated/0/脚本/") function zip压缩(srcpath) { /** * zip压缩文件夹/单文件 * 压缩后的zip文件存放在 文件/文件夹 的同级目录中 * 压缩成功返回压缩文件的绝对路径,压缩失败返回 mull * @param {string} srcpath 被压缩的文件夹/文件 绝对路径 */ importPackage(java.io) importPackage(java.util.zip) var f = new File(srcpath); if (!f.exists()) return null; var path = f.getPath(); var parent = f.getParentFile(); if (f.isDirectory()) { var zipName = path + ".zip"; } if (f.isFile()) { var zipName = parent + "/" + f.getName().split(".")[0] + ".zip"; } var zos = null; try { var fos2 = new FileOutputStream(new File(zipName)); zos = new ZipOutputStream(fos2); var sourceFile = new File(srcpath); compress(sourceFile, zos, sourceFile.getName(), true); } catch (e) { throw "zip error from ZipUtils: " + e } finally { if (zos != null) { try { zos.close(); return true; } catch (e) { log(e); return false; } } } function compress(sourceFile, zos, name, KeepDirStructure) { var buf = new util.java.array('byte', 4096); if (sourceFile.isFile()) { zos.putNextEntry(new ZipEntry(name)); var len; var ins = new FileInputStream(sourceFile); while ((len = ins.read(buf)) != -1) { zos.write(buf, 0, len); } zos.closeEntry(); ins.close(); } else { var listFiles = sourceFile.listFiles(); if (listFiles == null || listFiles.length == 0) { if (KeepDirStructure) { zos.putNextEntry(new ZipEntry(name + "/")); zos.closeEntry(); } } else { for (var f in listFiles) { var file = listFiles[f] if (KeepDirStructure) { compress(file, zos, name + "/" + file.getName(), KeepDirStructure); } else { compress(file, zos, file.getName(), KeepDirStructure); } } } } } } ``` ## zip文件解压 ```js //解压zip文件,可指定解压路径.若不指定,则解压到同级目录 function zip解压(zip全路径, 解压到目录) { let Zin = new java.util.zip.ZipInputStream(new java.io.FileInputStream(zip全路径)) //输入源zip路径 let Bin = new java.io.BufferedInputStream(Zin) let Parent = 解压到目录 //输出路径(文件夹目录) let Fout = null let entry while ((entry = Zin.getNextEntry()) != null && !entry.isDirectory()) { Fout = new java.io.File(Parent, entry.getName()) if (!Fout.exists()) { (new java.io.File(Fout.getParent())).mkdirs() } let out = new java.io.FileOutputStream(Fout); let Bout = new java.io.BufferedOutputStream(out) let b while ((b = Bin.read()) != -1) { Bout.write(b) } Bout.close() out.close() } Bin.close() Zin.close() } ```