JS 脚本规则

想用文本文件的第一行做文件名?想根据文件大小智能分类?普通规则做不到的复杂重命名,JS 脚本都能实现。

这个功能能帮你

  • 读取文件内容做文件名:用 txt/md 文件的第一行作为新文件名,自动整理笔记
  • 根据文件大小分类:给文件加上 [SMALL][MEDIUM][LARGE] 标签,一眼看出大小
  • 配置文件批量重命名:在文件夹放个 rename_rules.txt 配置文件,按规则自动处理
  • JavaScript 逻辑处理:if/else、正则、日期计算,写代码能做的都能做

快速上手(3步)

  1. 点击"添加规则"按钮 → 选 "JS 脚本"
  2. 选个示例开始:点击"Demo 示例"下拉框,选一个接近你需求的示例
  3. 先点预览看效果,没问题再点应用

具体例子

例子1:强制修改扩展名

❌ 原文件document.txtreport.docximage.png 😫 问题:想把所有文件的扩展名统一改成 .zip

✅ 代码

function main(file_name, file_path, file_index) {
  // 强制所有文件使用 .zip 扩展名
  return getFileNameExt(file_name).name + ".zip";
}

✅ 结果document.zipreport.zipimage.zip

为什么这样设置getFileNameExt 帮你分离文件名和扩展名,只需简单拼接即可。这是最简单的重命名逻辑。


例子2:用文本文件首行做前缀

❌ 原文件note.txt(内容第一行是"项目计划") 😫 问题:笔记文件名太随意,想用首行内容做前缀方便识别

✅ 代码

function main(file_name, file_path, file_index) {
  if (file_path == undefined) {
    return file_name;
  }

  const file_data = getFileNameExt(file_name);

  if (file_data.ext === ".txt" || file_data.ext === ".md") {
    try {
      // 读取文件内容
      const content = api.readTextFile(file_path);
      const lines = content.split('\n');
      const firstLine = lines[0] ? lines[0].trim() : '';

      if (firstLine) {
        // 清理文件名中的非法字符
        const cleanPrefix = firstLine
          .replace(/[<>:"/\\|?*]/g, '_')
          .substring(0, 20);
        console.log("首行前缀", cleanPrefix);
        return cleanPrefix + "_" + file_name;
      }
    } catch (error) {
      console.log("读取文件失败", error.message);
    }
  }

  return file_name;
}

✅ 结果项目计划_note.txt

为什么这样设置

  • 先判断 file_path 是否存在(某些情况下可能为空)
  • 只处理 .txt.md 文件
  • try...catch 避免读取失败导致中断
  • 清理非法字符,限制前缀长度避免文件名过长

例子3:根据文件大小标注

❌ 原文件photo.jpg(5.2MB) 😫 问题:想看文件名就知道大概大小,方便筛选

✅ 代码

function main(file_name, file_path, file_index) {
  if (file_path == undefined) {
    return file_name;
  }

  const file_data = getFileNameExt(file_name);

  try {
    const fileSizeBytes = api.getFileSize(file_path);
    let sizeCategory = "";
    let sizeLabel = "";

    if (fileSizeBytes < 1024) {
      sizeCategory = "TINY";
      sizeLabel = fileSizeBytes + "B";
    } else if (fileSizeBytes < 1024 * 1024) {
      sizeCategory = "SMALL";
      sizeLabel = Math.round(fileSizeBytes / 1024) + "KB";
    } else if (fileSizeBytes < 1024 * 1024 * 10) {
      sizeCategory = "MEDIUM";
      sizeLabel = Math.round(fileSizeBytes / (1024 * 1024)) + "MB";
    } else {
      sizeCategory = "LARGE";
      sizeLabel = Math.round(fileSizeBytes / (1024 * 1024)) + "MB";
    }

    return `[${sizeCategory}]_${sizeLabel}_${file_data.name}${file_data.ext}`;

  } catch (error) {
    console.log("获取文件大小失败", error.message);
    return file_name;
  }
}

✅ 结果[MEDIUM]_5MB_photo.jpg

为什么这样设置

  • 用 if/else 条件判断将文件分为 4 个等级
  • 自动换算单位(B/KB/MB)便于阅读
  • 模板字符串(反引号)方便拼接多个变量

函数和 API 参考

main 函数签名

所有 JS 脚本必须包含一个 main 函数,这是程序的入口:

function main(file_name, file_path, file_index) {
  // 你的重命名逻辑
  return 'new_name.txt'  // 必须返回新文件名
}

参数说明

参数类型说明示例
file_namestring原始文件名(含扩展名)"document.txt"
file_pathstring | undefined文件绝对路径(可能为 undefined)"/Users/xxx/document.txt"
file_indexnumber文件索引(从 0 开始)0, 1, 2

重要file_path 在某些情况下可能为 undefined(比如仅预览模式),使用前必须先判断:

if (file_path == undefined) {
  return file_name;
}

内置 API

API功能返回值限制
api.readTextFile(path)读取文本文件string最大 2MB
api.readLines(path)按行读取文件string[]最大 2MB
api.readBytes(path, offset, length)读取字节范围Uint8Array最大 256KB
api.getFileSize(path)获取文件大小(字节)number-

使用示例

// 读取整个文件
const content = api.readTextFile(file_path);

// 按行读取
const lines = api.readLines(file_path);
console.log("第一行:", lines[0]);

// 读取文件头部(前 100 字节)
const header = api.readBytes(file_path, 0, 100);

// 获取文件大小
const size = api.getFileSize(file_path);
console.log("文件大小:", size, "字节");

Helper 函数

getFileNameExt(file_name)

分离文件名和扩展名的工具函数:

const result = getFileNameExt("document.txt");
// 返回: { name: "document", ext: ".txt" }

const result2 = getFileNameExt("README");
// 返回: { name: "README", ext: "" }

返回值

  • name:不含扩展名的文件名
  • ext:扩展名(含点号前缀,如 .txt;无扩展名则为空字符串)

平台功能差异

Renamio 支持两个平台,部分功能存在差异:

uTools 平台

  • AI 代码生成:描述需求,AI 帮你写代码
  • AI 微调:改进现有代码的功能
  • ✅ 使用浏览器控制台查看 console.log 输出

Tauri 平台

  • 日志窗口:独立窗口显示 console.log 输出,打开方式:切换"日志窗口"开关
  • 测试代码:不实际重命名,只测试代码是否正常运行
  • ✅ 更安全的沙盒环境

核心功能完全相同:两个平台的 main 函数、内置 API、Helper 函数完全一致。

内置示例详解

点击"Demo 示例"下拉框可以快速加载 6 个内置示例:

1. Demo: Basic usage

完整的 API 文档注释,展示所有参数和内置函数的使用方法。适合初学者了解功能。

2. Convert extension to .zip

强制修改扩展名为 .zip,演示 getFileNameExt 的基本用法。

3. Delete last 2 characters

删除文件名末尾 2 个字符,演示边界检查(字符不足时保持原名)。

4. Use first line as prefix

用文本文件首行做前缀,演示:

  • api.readTextFile 读取文件
  • 文件类型判断(只处理 .txt.md
  • 非法字符清理

5. Annotate with file size

用文件大小标注文件名,演示:

  • api.getFileSize 获取文件大小
  • 条件判断进行分类(TINY/SMALL/MEDIUM/LARGE)
  • 单位换算和格式化输出

6. Rename by config file

根据同目录的 rename_rules.txt 配置文件重命名,演示:

  • 读取配置文件
  • 解析规则格式(pattern->replacement
  • 支持通配符 *
  • 模板变量替换({name}, {ext}, {index}, {date}

配置文件示例 (rename_rules.txt):

# 注释行,以 # 开头会被忽略
*.txt->文本_{name}{ext}
*.jpg->照片_{index}{ext}
*->文件_{date}_{name}{ext}

常见问题

❓ 为什么我的代码不执行?

  1. 检查是否包含 main 函数 代码必须包含 function main(file_name, file_path, file_index) { ... }

  2. 确保 main 函数有 return 必须返回新文件名,否则保持原名不变

  3. 查看日志输出

    • Tauri 平台:打开"日志窗口"开关
    • uTools 平台:打开浏览器开发者工具(F12)
  4. 检查语法错误 JavaScript 语法错误会导致整个脚本无法执行

❓ 怎么调试代码?

使用 console.log 输出中间变量:

function main(file_name, file_path, file_index) {
  console.log("文件名:", file_name);
  console.log("文件路径:", file_path);
  console.log("文件索引:", file_index);

  const file_data = getFileNameExt(file_name);
  console.log("分离结果:", file_data);

  return file_name;
}

查看输出

  • Tauri 平台:切换"日志窗口"开关,会打开独立窗口显示所有日志
  • uTools 平台:按 F12 打开浏览器控制台查看

Tauri 测试功能: 点击"测试代码"按钮,使用测试数据(file_name="test.txt", file_index=0)运行代码,不会实际重命名文件。

❓ 读取文件时报错怎么办?

  1. 检查 file_path 是否为 undefined

    if (file_path == undefined) {
      console.log("文件路径为空,跳过处理");
      return file_name;
    }
  2. try...catch 包裹文件读取代码

    try {
      const content = api.readTextFile(file_path);
      // 处理内容...
    } catch (error) {
      console.log("读取失败:", error.message);
      return file_name;  // 失败时保持原名
    }
  3. 确认文件大小在限制范围内

    • 文本读取(readTextFile, readLines):最大 2MB
    • 字节读取(readBytes):最大 256KB
  4. 检查文件是否存在 某些情况下文件路径可能失效,确保文件真实存在

❓ 如何处理不同类型的文件?

根据扩展名进行判断:

function main(file_name, file_path, file_index) {
  const file_data = getFileNameExt(file_name);

  if (file_data.ext === ".txt" || file_data.ext === ".md") {
    // 处理文本文件
    return "文本_" + file_name;
  } else if (file_data.ext === ".jpg" || file_data.ext === ".png") {
    // 处理图片文件
    return "图片_" + file_name;
  } else {
    // 其他文件
    return file_name;
  }
}

注意事项:

  • ⚠️ 文件路径可能为空:使用 file_path 前必须先判断 if (file_path == undefined)
  • ⚠️ 必须做错误处理:文件读取可能失败,用 try...catch 避免整个流程中断
  • ⚠️ 返回值必须是字符串main 函数必须 return 新文件名,否则保持原名
  • ⚠️ 非法字符会被过滤:文件名中的 [\\/:*?"<>|] 等字符系统会自动过滤或替换
  • ⚠️ 扩展名注意大小写.jpg.JPG 是不同的,建议统一转小写比较: file_data.ext.toLowerCase() === ".jpg"

进阶技巧

配合其他规则使用

  • 配合"序号生成":JS 脚本处理复杂逻辑(如读取文件内容),序号规则生成统一编号
  • 配合"日期规则":JS 脚本读取文件元数据,日期规则格式化时间戳
  • 配合"正则规则":JS 脚本做复杂判断(如文件类型分类),正则规则做文本替换

使用正则表达式

JavaScript 内置正则表达式支持:

function main(file_name, file_path, file_index) {
  // 提取文件名中的数字
  const match = file_name.match(/\d+/);
  if (match) {
    const number = parseInt(match[0]);
    return `序号${number}_${file_name}`;
  }
  return file_name;
}

处理日期和时间

使用 JavaScript 的 Date 对象:

function main(file_name, file_path, file_index) {
  const now = new Date();
  const dateStr = now.toISOString().slice(0, 10);  // 2024-01-15
  const file_data = getFileNameExt(file_name);
  return `${dateStr}_${file_data.name}${file_data.ext}`;
}

批量处理序号

利用 file_index 参数生成自定义序号:

function main(file_name, file_path, file_index) {
  // 从 1 开始,补齐 3 位数字
  const serial = String(file_index + 1).padStart(3, '0');
  const file_data = getFileNameExt(file_name);
  return `${serial}_${file_data.name}${file_data.ext}`;
}

下一步看看什么?