EasyClick 入门指南(十七):文件操作完全指南

EasyClick 入门指南(十七):文件操作完全指南

本文基于 EasyClick 官方文档整理

目录

  1. 前言
  2. 三平台API差异概览
  3. [Android 平台文件操作](#Android 平台文件操作 "#%E4%B8%89android-%E5%B9%B3%E5%8F%B0%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C")
  4. [iOS USB版 文件操作](#iOS USB版 文件操作 "#%E5%9B%9Bios-usb%E7%89%88-%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C")
  5. [iOS 脱机版 文件操作](#iOS 脱机版 文件操作 "#%E4%BA%94ios-%E8%84%B1%E6%9C%BA%E7%89%88-%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C")
  6. [鸿蒙 Next 平台文件操作](#鸿蒙 Next 平台文件操作 "#%E5%85%AD%E9%B8%BF%E8%92%99-next-%E5%B9%B3%E5%8F%B0%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C")
  7. [Excel 数据解析(iOS/鸿蒙)](#Excel 数据解析(iOS/鸿蒙) "#%E4%B8%83excel-%E6%95%B0%E6%8D%AE%E8%A7%A3%E6%9E%90ios%E9%B8%BF%E8%92%99")
  8. 常见问题

一、前言

为什么需要文件操作?

在自动化脚本中,文件操作是不可或缺的基础能力:

  • 日志记录:保存脚本执行日志,方便排查问题
  • 配置持久化:保存用户配置、任务状态
  • 数据缓存:本地缓存 API 数据,减少网络请求
  • 文件处理:读取 Excel、解析 CSV、批量处理文件
  • 素材管理:截图保存、安装包管理

EasyClick 文件模块特点

  • 支持读写文本文件
  • 支持 Excel 文件(iOS 4.0.0+ / 鸿蒙 1.0.0+)
  • 支持文件夹遍历、批量操作
  • 三平台通用 API 保持一致
  • iOS/鸿蒙使用沙盒路径管理

二、三平台API差异概览

2.1 运行环境说明

平台 运行环境 文件操作说明
Android 设备端 直接操作设备文件系统
iOS USB版 PC端中控 可操作PC本地文件连接设备的沙盒文件
iOS 脱机版 设备端 仅可操作应用沙盒内文件
鸿蒙 PC端中控 可操作PC本地文件连接设备的沙盒文件

注意:iOS USB版和鸿蒙版类似,都运行在PC端中控,支持PC本地路径和设备沙盒路径两种模式。 iOS 脱机版运行在设备端,只能使用沙盒路径。

2.2 通用API(三平台共有)

以下API在 Android、iOS(USB/脱机)、鸿蒙三平台通用:

API 功能说明
file.readFile(path) 读取文件为字符串
file.writeFile(data, path) 写入文件(覆盖模式)
file.readLine(path, lineNo) 读取指定行
file.appendLine(data, path) 追加一行到文件
file.readAllLines(path) 读取所有行到数组
file.deleteLine(path, line, contains) 删除指定行或匹配行
file.listDir(path) 列出目录下所有文件(递归)
file.create(path) 创建空文件
file.mkdirs(path) 创建文件夹(支持多级)
file.deleteAllFile(path) 删除文件或文件夹
file.exists(path) 检查文件是否存在
file.copy(src, dest) 复制文件

2.3 平台特有API

API Android iOS USB iOS 脱机 鸿蒙 说明
file.readAssets(path) 读取APK assets文件
file.getSandBoxDir() 获取沙盒根目录
file.getSandBoxFilePath(name) 拼接沙盒文件路径
file.getInternalDir(type) 获取内部存储地址(脱机版特有)
file.readExcelRow(path, sheet, row) 读取Excel一行
file.readExcelAllRow(path, sheet) 读取Excel所有数据
file.listDir2(path, recursion) 列出文件(可配置是否递归,脱机版特有)
file.readLineEx(path, lineNo) 读取一行(适合大文件,脱机版特有)
file.appendLineEx(data, path) 追加一行(适合大文件,脱机版特有)
file.deleteLineEx(path, line, contains) 删除行(适合大文件,脱机版特有)

2.4 文件路径差异

平台 路径写法 示例
Android 直接写绝对路径 /sdcard/test.txt
iOS USB版 PC本地路径设备沙盒路径 D:/test.txtfile.getSandBoxFilePath("test.txt")
iOS 脱机版 沙盒路径 使用 file.getSandBoxFilePath("test.txt")
鸿蒙 PC本地路径设备沙盒路径 D:/test.txtfile.getSandBoxFilePath("test.txt")

三、Android 平台文件操作

3.1 文件路径

Android 平台可以直接使用绝对路径访问外部存储:

javascript 复制代码
/**
 * Android 平台文件路径示例
 */
function androidFilePath() {
  // 直接写绝对路径
  var filePath = "/sdcard/test.txt";
  var dirPath = "/sdcard/easyclick/logs/";

  // 检查文件是否存在
  if (file.exists(filePath)) {
    logd("文件存在: " + filePath);
  } else {
    logd("文件不存在: " + filePath);
  }

  // 确保目录存在
  if (!file.exists(dirPath)) {
    file.mkdirs(dirPath);
    logd("创建目录: " + dirPath);
  }
}

3.2 读取文件

javascript 复制代码
/**
 * Android: 读取整个文件为字符串
 */
function readFileAndroid() {
  var filePath = "/sdcard/config.json";

  // 检查文件是否存在
  if (!file.exists(filePath)) {
    loge("文件不存在: " + filePath);
    return null;
  }

  // 读取文件内容
  var content = file.readFile(filePath);

  if (content) {
    logd("文件内容:\n" + content);
    return content;
  } else {
    loge("读取失败");
    return null;
  }
}

3.3 逐行读取

javascript 复制代码
/**
 * Android: 逐行读取文件
 */
function readLineByLineAndroid() {
  var filePath = "/sdcard/app.log";
  var lineNo = 1;
  var maxLines = 100;

  while (lineNo <= maxLines) {
    var line = file.readLine(filePath, lineNo);

    if (!line) {
      logd("到达文件末尾,已读取 " + (lineNo - 1) + " 行");
      break;
    }

    logd("第 " + lineNo + " 行: " + line);

    // 过滤包含 ERROR 的行
    if (line.indexOf("ERROR") >= 0) {
      loge("发现错误: " + line);
    }

    lineNo++;
  }
}

3.4 写入文件

javascript 复制代码
/**
 * Android: 写入文件(覆盖模式)
 */
function writeFileAndroid() {
  var filePath = "/sdcard/output.txt";

  var content = "Hello EasyClick!\n" + "这是第一行数据\n" + "这是第二行数据";

  var result = file.writeFile(content, filePath);

  if (result) {
    logd("写入成功");
  } else {
    loge("写入失败");
  }
}

3.5 追加写入

javascript 复制代码
/**
 * Android: 追加写入文件(适合日志)
 */
function appendToLogAndroid() {
  var logFile = "/sdcard/script.log";

  file.appendLine("[2024-01-01 10:00:00] 脚本启动", logFile);
  file.appendLine("[2024-01-01 10:00:05] 任务开始执行", logFile);
  file.appendLine("[2024-01-01 10:00:10] 点击按钮成功", logFile);

  logd("日志已追加写入");
}

3.6 文件夹操作

javascript 复制代码
/**
 * Android: 创建文件夹
 */
function createFolderAndroid() {
  var dirPath = "/sdcard/easyclick/projects/";

  var result = file.mkdirs(dirPath);

  if (result) {
    logd("文件夹创建成功: " + dirPath);
  } else {
    loge("文件夹创建失败");
  }
}

/**
 * Android: 列出文件夹内容
 */
function listFilesAndroid() {
  var dirPath = "/sdcard/";

  var files = file.listDir(dirPath);

  if (files) {
    logd("目录下共有 " + files.length + " 个文件/文件夹:");

    for (var i = 0; i < files.length; i++) {
      var fileName = files[i].substring(files[i].lastIndexOf("/") + 1);
      logd("  " + (i + 1) + ". " + fileName);
    }
  }
}

3.7 文件增删改查

javascript 复制代码
/**
 * Android: 创建文件
 */
function createFileAndroid() {
  var filePath = "/sdcard/new_file.txt";

  if (file.exists(filePath)) {
    logd("文件已存在");
    return false;
  }

  var result = file.create(filePath);

  if (result) {
    logd("文件创建成功");
    file.writeFile("初始化内容", filePath);
    return true;
  } else {
    loge("文件创建失败");
    return false;
  }
}

/**
 * Android: 删除文件/文件夹
 */
function deleteFileAndroid() {
  var result1 = file.deleteAllFile("/sdcard/temp.txt");
  logd("删除文件: " + (result1 ? "成功" : "失败"));

  var result2 = file.deleteAllFile("/sdcard/temp_dir/");
  logd("删除文件夹: " + (result2 ? "成功" : "失败"));
}

/**
 * Android: 复制文件
 */
function copyFileAndroid() {
  var srcPath = "/sdcard/source.txt";
  var destPath = "/sdcard/backup/source.txt";
  var destDir = "/sdcard/backup/";

  // 确保目标目录存在
  if (!file.exists(destDir)) {
    file.mkdirs(destDir);
  }

  var result = file.copy(srcPath, destPath);
  logd("复制: " + (result ? "成功" : "失败"));
}

/**
 * Android: 删除指定行
 *
 * 参数说明:
 * - line: 行号,从1开始。如果为-1,则按contains条件删除
 * - contains: 包含的字符串,如果为null则按行号删除
 *
 * 使用规则:
 * - line > 0, contains = null: 删除指定行号
 * - line = -1, contains = "xxx": 删除包含"xxx"的行
 */
function deleteLinesAndroid() {
  var filePath = "/sdcard/data.txt";

  // 删除第3行 (line=3, contains=null: 按行号删除)
  var result1 = file.deleteLine(filePath, 3, null);
  logd("删除第3行: " + (result1 ? "成功" : "失败"));

  // 删除包含 ERROR 的行 (line=-1: 按包含条件删除)
  var result2 = file.deleteLine(filePath, -1, "ERROR");
  logd("删除包含 ERROR 的行: " + (result2 ? "成功" : "失败"));
}

3.8 读取Assets(Android特有)

javascript 复制代码
/**
 * Android: 读取APK assets文件
 */
function readAssetsAndroid() {
  // 读取 assets/data/config.json
  var data = file.readAssets("data/config.json");
  logd("Assets内容: " + data);
}

iOS 平台文件操作

重要区别:iOS 有两个版本,文件操作方式不同:

  • iOS USB版:运行在PC端中控,支持PC本地路径和设备沙盒路径
  • iOS 脱机版:运行在设备端,只能使用沙盒路径

四、iOS USB版 文件操作

iOS USB版运行在PC端中控,与鸿蒙版类似,支持两种路径模式。

4.1 两种路径模式

javascript 复制代码
/**
 * iOS USB版: 两种路径模式说明
 */
function iosUsbFilePath() {
  // 模式1:PC本地路径(直接操作电脑文件)
  var pcPath = "D:/test.txt";
  var pcDir = "D:/easyclick/data/";

  logd("PC本地路径: " + pcPath);

  // 模式2:设备沙盒路径(操作连接设备的文件)
  // 获取当前设备的沙盒根目录
  var sandboxDir = file.getSandBoxDir();
  logd("设备沙盒根目录: " + sandboxDir);

  // 拼接设备沙盒中的文件路径
  var deviceConfigPath = file.getSandBoxFilePath("config.json");
  var deviceLogPath = file.getSandBoxFilePath("logs/app.log");

  logd("设备配置文件: " + deviceConfigPath);
  logd("设备日志文件: " + deviceLogPath);
}

4.2 PC本地文件操作

javascript 复制代码
/**
 * iOS USB版: 操作PC本地文件
 */
function readFilePC_IOS() {
  // 操作PC本地文件
  var filePath = "D:/config.json";

  if (!file.exists(filePath)) {
    loge("文件不存在: " + filePath);
    return null;
  }

  var content = file.readFile(filePath);
  logd("PC文件内容: " + content);
  return content;
}

/**
 * iOS USB版: 写入PC本地文件
 */
function writeFilePC_IOS() {
  var filePath = "D:/output.txt";

  var result = file.writeFile("iOS USB版PC端写入测试", filePath);
  logd("PC文件写入: " + (result ? "成功" : "失败"));
}

/**
 * iOS USB版: PC本地日志
 */
function appendLogPC_IOS() {
  var logFile = "D:/logs/app.log";

  // 确保日志目录存在
  var logDir = "D:/logs/";
  if (!file.exists(logDir)) {
    file.mkdirs(logDir);
  }

  file.appendLine("[" + new Date().toISOString() + "] PC端日志", logFile);
  logd("PC日志已追加");
}

4.3 设备沙盒文件操作

javascript 复制代码
/**
 * iOS USB版: 读取设备沙盒文件
 */
function readFileDevice_IOS() {
  // 操作连接设备的沙盒文件
  var filePath = file.getSandBoxFilePath("config.json");

  if (!file.exists(filePath)) {
    loge("设备文件不存在");
    return null;
  }

  var content = file.readFile(filePath);
  logd("设备文件内容: " + content);
  return content;
}

/**
 * iOS USB版: 写入设备沙盒文件
 */
function writeFileDevice_IOS() {
  var filePath = file.getSandBoxFilePath("output.txt");

  var result = file.writeFile("设备沙盒写入测试", filePath);
  logd("设备文件写入: " + (result ? "成功" : "失败"));
}

/**
 * iOS USB版: 创建设备沙盒文件夹
 */
function createDeviceFolder_IOS() {
  var dirPath = file.getSandBoxFilePath("projects/");
  var result = file.mkdirs(dirPath);
  logd("创建设备文件夹: " + (result ? "成功" : "失败"));
}

/**
 * iOS USB版: 列出设备沙盒文件
 */
function listDeviceFiles_IOS() {
  var sandboxDir = file.getSandBoxDir();
  var files = file.listDir(sandboxDir);

  if (files) {
    logd("设备沙盒文件数: " + files.length);
  }
}

五、iOS 脱机版 文件操作

iOS 脱机版运行在设备端,只能使用沙盒路径,不能访问PC本地路径。

5.1 沙盒路径

javascript 复制代码
/**
 * iOS 脱机版: 沙盒路径使用
 */
function iosOfflineFilePath() {
  // 获取沙盒根目录
  var sandboxDir = file.getSandBoxDir();
  logd("沙盒根目录: " + sandboxDir);

  // 拼接沙盒文件路径(推荐)
  var configPath = file.getSandBoxFilePath("config.json");
  var logPath = file.getSandBoxFilePath("logs/app.log");

  logd("配置文件: " + configPath);
  logd("日志文件: " + logPath);
}

/**
 * iOS 脱机版: 获取内部存储地址(脱机版特有)
 */
function getInternalDir_IOS() {
  // documents, library, temp, libraryCaches
  // documents文件夹类型可以通过爱思导出
  var docPath = file.getInternalDir("documents");
  logd("Documents路径: " + docPath);

  var tempPath = file.getInternalDir("temp");
  logd("Temp路径: " + tempPath);
}

5.2 读取文件

javascript 复制代码
/**
 * iOS 脱机版: 读取文件
 */
function readFileIOS_Offline() {
  // 使用沙盒路径
  var filePath = file.getSandBoxFilePath("config.json");

  if (!file.exists(filePath)) {
    loge("文件不存在: " + filePath);
    return null;
  }

  var content = file.readFile(filePath);

  if (content) {
    logd("文件内容:\n" + content);
    return content;
  } else {
    loge("读取失败");
    return null;
  }
}

5.3 写入文件

javascript 复制代码
/**
 * iOS 脱机版: 写入文件
 */
function writeFileIOS_Offline() {
  var filePath = file.getSandBoxFilePath("output.txt");

  var content = "Hello EasyClick!\n" + "iOS 脱机版沙盒写入测试";

  var result = file.writeFile(content, filePath);
  logd("写入: " + (result ? "成功" : "失败"));
}

/**
 * iOS 脱机版: 追加日志
 */
function appendLogIOS_Offline() {
  var logFile = file.getSandBoxFilePath("app.log");

  file.appendLine("[" + new Date().toISOString() + "] 日志内容", logFile);
  logd("日志已追加");
}

5.4 文件夹操作

javascript 复制代码
/**
 * iOS 脱机版: 创建文件夹
 */
function createFolderIOS_Offline() {
  var dirPath = file.getSandBoxFilePath("easyclick/projects/");

  var result = file.mkdirs(dirPath);
  logd("创建文件夹: " + (result ? "成功" : "失败"));
}

/**
 * iOS 脱机版: 列出沙盒文件(递归)
 */
function listFilesIOS_Offline() {
  var dirPath = file.getSandBoxDir();

  // listDir 默认递归列出所有子文件夹
  var files = file.listDir(dirPath);

  if (files) {
    logd("沙盒下共有 " + files.length + " 个文件:");

    for (var i = 0; i < files.length; i++) {
      var fileName = files[i].substring(files[i].lastIndexOf("/") + 1);
      logd("  " + (i + 1) + ". " + fileName);
    }
  }
}

/**
 * iOS 脱机版: 列出文件(可配置是否递归)
 * 适配EC脱机 4.1.0+,脱机版特有API
 */
function listFilesIOS_NoRecurse() {
  var dirPath = file.getSandBoxDir();

  // listDir2 可以配置是否递归
  // 第二个参数: true=递归, false=不递归
  var files = file.listDir2(dirPath, false);

  if (files) {
    logd("当前目录下共有 " + files.length + " 个文件/文件夹");
  }
}

5.5 文件增删改查

javascript 复制代码
/**
 * iOS 脱机版: 文件操作示例
 */
function fileOperationsIOS_Offline() {
  // 创建文件
  var filePath = file.getSandBoxFilePath("test.txt");

  if (!file.exists(filePath)) {
    file.create(filePath);
    file.writeFile("初始化内容", filePath);
    logd("文件已创建");
  }

  // 复制文件
  var backupPath = file.getSandBoxFilePath("test_backup.txt");
  file.copy(filePath, backupPath);
  logd("文件已备份");

  // 删除文件
  // file.deleteAllFile(filePath);
}

/**
 * iOS 脱机版: 删除指定行
 */
function deleteLinesIOS_Offline() {
  var filePath = file.getSandBoxFilePath("data.txt");

  // 删除第3行
  var result1 = file.deleteLine(filePath, 3, null);
  logd("删除第3行: " + (result1 ? "成功" : "失败"));

  // 删除包含 ERROR 的行
  var result2 = file.deleteLine(filePath, -1, "ERROR");
  logd("删除包含 ERROR 的行: " + (result2 ? "成功" : "失败"));
}

/**
 * iOS 脱机版: 大文件操作(Ex系列API,脱机版特有)
 * 适配 EC 4.7.3+
 */
function largeFileOperationsIOS_Offline() {
  var filePath = file.getSandBoxFilePath("large.log");

  // readLineEx - 适合大文件的读取一行
  var line = file.readLineEx(filePath, 1000);
  logd("第1000行: " + line);

  // appendLineEx - 适合大文件的追加写入
  var result = file.appendLineEx("新日志内容", filePath);
  logd("追加: " + (result ? "成功" : "失败"));

  // deleteLineEx - 适合大文件的删除行
  var delResult = file.deleteLineEx(filePath, -1, "过期数据");
  logd("删除包含'过期数据'的行: " + (delResult ? "成功" : "失败"));
}

六、鸿蒙 Next 平台文件操作

注意:鸿蒙版运行在PC端中控,支持两种路径:

  1. PC本地路径 (如 D:/test.txt)- 直接操作电脑文件
  2. 设备沙盒路径 (通过 getSandBoxFilePath)- 操作连接设备的沙盒文件

6.1 两种路径模式

javascript 复制代码
/**
 * 鸿蒙: 两种路径模式说明
 */
function harmonyFilePath() {
  // 模式1:PC本地路径(直接操作电脑文件)
  var pcPath = "D:/test.txt";
  var pcDir = "D:/easyclick/data/";

  logd("PC本地路径: " + pcPath);

  // 模式2:设备沙盒路径(操作连接设备的文件)
  // 获取当前设备的沙盒根目录
  var sandboxDir = file.getSandBoxDir();
  logd("设备沙盒根目录: " + sandboxDir);

  // 拼接设备沙盒中的文件路径
  var deviceConfigPath = file.getSandBoxFilePath("config.json");
  var deviceLogPath = file.getSandBoxFilePath("logs/app.log");

  logd("设备配置文件: " + deviceConfigPath);
  logd("设备日志文件: " + deviceLogPath);
}

6.2 PC本地文件操作

javascript 复制代码
/**
 * 鸿蒙: 操作PC本地文件
 */
function readFilePCHarmony() {
  // 操作PC本地文件
  var filePath = "D:/config.json";

  if (!file.exists(filePath)) {
    loge("文件不存在: " + filePath);
    return null;
  }

  var content = file.readFile(filePath);
  logd("PC文件内容: " + content);
  return content;
}

/**
 * 鸿蒙: 写入PC本地文件
 */
function writeFilePCHarmony() {
  var filePath = "D:/output.txt";

  var result = file.writeFile("鸿蒙PC端写入测试", filePath);
  logd("PC文件写入: " + (result ? "成功" : "失败"));
}

/**
 * 鸿蒙: PC本地日志
 */
function appendLogPCHarmony() {
  var logFile = "D:/logs/app.log";

  // 确保日志目录存在
  var logDir = "D:/logs/";
  if (!file.exists(logDir)) {
    file.mkdirs(logDir);
  }

  file.appendLine("[" + new Date().toISOString() + "] PC端日志", logFile);
  logd("PC日志已追加");
}

6.3 设备沙盒文件操作

javascript 复制代码
/**
 * 鸿蒙: 读取设备沙盒文件
 */
function readFileDeviceHarmony() {
  // 操作连接设备的沙盒文件
  var filePath = file.getSandBoxFilePath("data.txt");

  if (!file.exists(filePath)) {
    loge("设备文件不存在");
    return null;
  }

  var content = file.readFile(filePath);
  logd("设备文件内容: " + content);
  return content;
}

/**
 * 鸿蒙: 写入设备沙盒文件
 */
function writeFileDeviceHarmony() {
  var filePath = file.getSandBoxFilePath("output.txt");

  var result = file.writeFile("设备沙盒写入测试", filePath);
  logd("设备文件写入: " + (result ? "成功" : "失败"));
}

/**
 * 鸿蒙: 创建设备沙盒文件夹
 */
function createDeviceFolderHarmony() {
  var dirPath = file.getSandBoxFilePath("projects/");
  var result = file.mkdirs(dirPath);
  logd("创建设备文件夹: " + (result ? "成功" : "失败"));
}

/**
 * 鸿蒙: 列出设备沙盒文件
 */
function listDeviceFilesHarmony() {
  var sandboxDir = file.getSandBoxDir();
  var files = file.listDir(sandboxDir);

  if (files) {
    logd("设备沙盒文件数: " + files.length);
  }
}

七、Excel 数据解析(iOS/鸿蒙)

⚠️ 注意:Excel API 仅支持 iOS 4.0.0+ 和 鸿蒙 1.0.0+,Android 平台官方API暂不支持(需要自行Java插件实现)。

7.1 iOS 读取 Excel

javascript 复制代码
/**
 * iOS: 读取 Excel 指定行
 * 适合版本: EC iOS 4.0.0+
 */
function readExcelRowIOS() {
  // iOS 直接使用文件名(相对于沙盒)
  var excelPath = "users.xlsx";

  var sheetIndex = 0; // 第1个工作表
  var rowIndex = 1; // 第2行(第0行是表头)

  var rowData = file.readExcelRow(excelPath, sheetIndex, rowIndex);

  if (rowData) {
    logd("第 " + (rowIndex + 1) + " 行数据:");
    for (var key in rowData) {
      logd("  " + key + ": " + rowData[key]);
    }
  }
}

/**
 * iOS: 读取 Excel 所有数据
 * 适合版本: EC iOS 4.0.0+
 */
function readExcelAllIOS() {
  var excelPath = "users.xlsx";
  var sheetIndex = 0;

  var allData = file.readExcelAllRow(excelPath, sheetIndex);

  if (allData) {
    logd("共读取 " + allData.length + " 条记录");

    for (var i = 0; i < allData.length; i++) {
      var row = allData[i];
      logd("记录 " + (i + 1) + ":");
      logd("  姓名: " + row.姓名);
      logd("  年龄: " + row.年龄);
    }
  }
}

7.2 鸿蒙读取 Excel

鸿蒙版Excel文件可以放在PC本地或设备沙盒中

javascript 复制代码
/**
 * 鸿蒙: 从PC本地读取 Excel
 * 适合版本: EC 鸿蒙 1.0.0+
 */
function readExcelRowHarmonyPC() {
  // 从PC本地路径读取
  var excelPath = "D:/data/users.xlsx";
  var sheetIndex = 0;
  var rowIndex = 1;

  var rowData = file.readExcelRow(excelPath, sheetIndex, rowIndex);

  if (rowData) {
    logd("第 " + (rowIndex + 1) + " 行数据:");
    for (var key in rowData) {
      logd("  " + key + ": " + rowData[key]);
    }
  }
}

/**
 * 鸿蒙: 从设备沙盒读取 Excel
 * 适合版本: EC 鸿蒙 1.0.0+
 */
function readExcelRowHarmonyDevice() {
  // 从设备沙盒读取(直接使用文件名)
  var excelPath = "users.xlsx";
  var sheetIndex = 0;
  var rowIndex = 1;

  var rowData = file.readExcelRow(excelPath, sheetIndex, rowIndex);

  if (rowData) {
    logd("第 " + (rowIndex + 1) + " 行数据:");
    for (var key in rowData) {
      logd("  " + key + ": " + rowData[key]);
    }
  }
}

/**
 * 鸿蒙: 读取 Excel 所有数据
 * 适合版本: EC 鸿蒙 1.0.0+
 */
function readExcelAllHarmony() {
  // 可以从PC本地或设备沙盒读取
  var excelPath = "users.xlsx"; // 设备沙盒
  // var excelPath = "D:/data/users.xlsx";  // PC本地

  var sheetIndex = 0;

  var allData = file.readExcelAllRow(excelPath, sheetIndex);

  if (allData) {
    logd("共读取 " + allData.length + " 条记录");

    for (var i = 0; i < allData.length; i++) {
      var row = allData[i];
      logd("记录 " + (i + 1) + ":");
      logd("  姓名: " + row.姓名);
      logd("  年龄: " + row.年龄);
    }
  }
}

7.3 批量处理 Excel 数据(iOS/鸿蒙)

javascript 复制代码
/**
 * 从 Excel 读取数据并执行自动化操作
 * 适用于 iOS 4.0.0+ / 鸿蒙 1.0.0+
 */
function batchProcessFromExcel() {
  var excelPath = "tasks.xlsx";

  // 读取所有任务
  var tasks = file.readExcelAllRow(excelPath, 0);

  if (!tasks) {
    loge("读取任务失败");
    return;
  }

  logd("共找到 " + tasks.length + " 个任务");

  // 逐个执行任务
  for (var i = 0; i < tasks.length; i++) {
    var task = tasks[i];

    logd("执行任务 " + (i + 1) + ": " + task.任务名称);

    try {
      executeTask(task);
      logd("任务完成");
    } catch (e) {
      loge("任务执行失败: " + e.message);
    }
  }
}

function executeTask(task) {
  switch (task.操作类型) {
    case "登录":
      login(task.用户名, task.密码);
      break;
    case "提交":
      submitForm(task.表单内容);
      break;
    case "截图":
      captureScreen(task.保存路径);
      break;
    default:
      loge("未知操作类型: " + task.操作类型);
  }
}

function login(username, password) {
  logd("执行登录: " + username);
}

function submitForm(content) {
  logd("提交表单: " + content);
}

function captureScreen(path) {
  logd("截图保存: " + path);
}

八、常见问题

Q1: 文件读写失败怎么办?

javascript 复制代码
// 1. 检查路径是否正确
var filePath = "/sdcard/test.txt"; // Android
// var filePath = file.getSandBoxFilePath("test.txt");  // iOS脱机版/鸿蒙设备沙盒
// var filePath = "D:/test.txt";  // iOS USB版/鸿蒙PC本地

logd("检查文件: " + file.exists(filePath));

// 2. 检查目录是否存在
var dirPath = "/sdcard/mydir/"; // Android
// var dirPath = file.getSandBoxFilePath("mydir/");  // iOS脱机版/鸿蒙设备沙盒
// var dirPath = "D:/mydir/";  // iOS USB版/鸿蒙PC本地

if (!file.exists(dirPath)) {
  file.mkdirs(dirPath);
  logd("目录不存在,已创建");
}

// 3. Android 需要存储权限
// iOS脱机版/鸿蒙设备沙盒无需额外权限
// iOS USB版/鸿蒙PC本地路径无需额外权限

Q2: iOS/鸿蒙如何查看沙盒文件?

javascript 复制代码
// iOS脱机版: 获取沙盒路径并打印
var sandboxDir = file.getSandBoxDir();
logd("iOS沙盒路径: " + sandboxDir);

// iOS USB版/鸿蒙: 获取设备沙盒路径
var deviceSandboxDir = file.getSandBoxDir();
logd("设备沙盒路径: " + deviceSandboxDir);

// 使用 EasyClick IDE 的文件管理器查看
// 或通过 iTunes 文件共享导出(iOS脱机版如支持)

Q3: iOS USB版/鸿蒙版如何选择PC本地路径还是设备沙盒路径?

javascript 复制代码
/**
 * iOS USB版/鸿蒙版两种路径模式选择指南
 */

// 场景1:配置文件、日志文件放在PC本地(推荐)
// 优点:方便查看和管理,重启后保留
var pcConfigPath = "D:/easyclick/config.json";
var pcLogPath = "D:/easyclick/logs/app.log";

// 场景2:临时数据、截图等放在设备沙盒
// 优点:与设备关联,多设备隔离
var deviceTempPath = file.getSandBoxFilePath("temp/data.tmp");
var deviceScreenshotPath = file.getSandBoxFilePath("screenshots/");

// 场景3:Excel数据文件可以放在任意位置
var excelPathPC = "D:/data/users.xlsx"; // PC本地
var excelPathDevice = "users.xlsx"; // 设备沙盒

Q4: 大文件读取内存溢出怎么办?

javascript 复制代码
// 使用 readLine 逐行读取,避免一次性加载
function readLargeFile() {
  var filePath = "/sdcard/big.log"; // Android
  // var filePath = file.getSandBoxFilePath("big.log");  // iOS/鸿蒙设备沙盒
  // var filePath = "D:/logs/big.log";  // 鸿蒙PC本地

  for (var i = 1; i <= 10000; i++) {
    var line = file.readLine(filePath, i);
    if (!line) break;
    logd("第 " + i + " 行: " + line);
  }
}

Q5: 如何递归遍历所有子文件夹?

javascript 复制代码
// 递归遍历函数(三平台通用)
function recursiveListDir(dirPath) {
  var files = file.listDir(dirPath);

  if (!files) return;

  for (var i = 0; i < files.length; i++) {
    var fullPath = files[i];
    var fileName = fullPath.substring(fullPath.lastIndexOf("/") + 1);

    // 判断是否为文件夹(无扩展名或以/结尾)
    if (fileName.indexOf(".") < 0 || fullPath.endsWith("/")) {
      // 是文件夹,递归遍历
      recursiveListDir(fullPath);
    } else {
      // 是文件,处理
      logd("文件: " + fullPath);
    }
  }
}

// Android 使用
recursiveListDir("/sdcard/");

// iOS脱机版 使用
// recursiveListDir(file.getSandBoxDir());

// iOS USB版/鸿蒙 PC本地使用
// recursiveListDir("D:/easyclick/");

// iOS USB版/鸿蒙 设备沙盒使用
// recursiveListDir(file.getSandBoxDir());

Q6: iOS脱机版有哪些特有的大文件API?

iOS脱机版提供了Ex系列API,专门用于处理大文件,避免内存溢出:

javascript 复制代码
/**
 * iOS脱机版特有的大文件API(适配EC 4.7.3+)
 */
function largeFileOperationsIOS() {
  var filePath = file.getSandBoxFilePath("large.log");

  // readLineEx - 适合大文件的读取一行
  var line = file.readLineEx(filePath, 1000);
  logd("第1000行: " + line);

  // appendLineEx - 适合大文件的追加写入
  var result = file.appendLineEx("新日志内容", filePath);
  logd("追加: " + (result ? "成功" : "失败"));

  // deleteLineEx - 适合大文件的删除行
  var delResult = file.deleteLineEx(filePath, -1, "过期数据");
  logd("删除包含'过期数据'的行: " + (delResult ? "成功" : "失败"));
}

/**
 * iOS脱机版: 可配置递归的目录遍历(适配EC脱机 4.1.0+)
 */
function listDirWithConfig_IOS() {
  var dirPath = file.getSandBoxDir();

  // listDir2 可以配置是否递归
  // 第二个参数: true=递归, false=不递归
  var files = file.listDir2(dirPath, false);
  logd("当前目录文件数: " + files.length);
}

Q7: Android 能否使用 Excel API?

根据官方文档,Android 平台暂不支持 file.readExcelRowfile.readExcelAllRow API。如需在 Android 处理 Excel,建议:

  1. 使用第三方库实现Java插件方式解析 Excel
  2. 将 Excel 转换为 CSV 格式处理
  3. 通过 HTTP 接口在服务端处理

结语

本文基于 EasyClick 官方文档整理,各平台API以知识库为准:

平台 运行环境 通用API 特有API
Android 设备端 ✅ 全部通用 file.readAssets
iOS USB版 PC端中控 ✅ 全部通用 file.getSandBoxDir, file.getSandBoxFilePath, file.readExcelRow, file.readExcelAllRow
iOS 脱机版 设备端 ✅ 全部通用 file.getSandBoxDir, file.getSandBoxFilePath, file.readExcelRow, file.readExcelAllRow, file.getInternalDir, file.listDir2, file.readLineEx, file.appendLineEx, file.deleteLineEx
鸿蒙 PC端中控 ✅ 全部通用 file.getSandBoxDir, file.getSandBoxFilePath, file.readExcelRow, file.readExcelAllRow

相关资源:

复制代码
相关推荐
技术落地手记21 小时前
一个需求 ID 换一份完整测试用例,我让 AI 替测试同事省掉半天
单元测试·测试
暗冰ཏོ2 天前
软件测试完整学习指南:从入门到自动化、性能与安全测试实战
软件测试·功能测试·单元测试·集成测试·压力测试·测试·安全性测试
弹简特2 天前
【接口自动化】02-Pytest固件fixture核心机制与Allure企业级报告实战
自动化·pytest·测试
钧界编程3 天前
EasyClick 入门指南(九):异常处理与脚本健壮性 —— 从“不堪一击”到“金刚不坏”
测试
大刚测试开发实战3 天前
TestHub测试平台整体功能简介
django·llm·测试
ClouGence3 天前
不用写 Selenium,零代码的 UI 自动化测试工具!
selenium·测试
大刚测试开发实战3 天前
年度重磅!TestHub测试平台正式开源!
github·测试
tang&5 天前
【测试】Web页面UI自动化测试完全指南:8步通用测试框架
ui·测试