🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

daji

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

daji - npm Package Compare versions

Comparing version
2.0.1
to
2.0.2
+4
-0
bin/index.js

@@ -139,2 +139,6 @@ #!/usr/bin/env node

.option('-p, --prefix <string>', '自定义前缀,默认P', 'P')
.option('-d, --dir', '递归处理子目录')
.option('-num, --number <number>', '序号位数,默认5位', 5)
.option('-type, --type <types...>', '文件类型,支持多个类型,如: jpg png gif')
.option('-forceDir, --forceDir', '强制重命名文件夹,从1开始自增')
.action((options, command) => {

@@ -141,0 +145,0 @@ const cmd = command.args[0];

@@ -30,2 +30,6 @@ # 文件重命名模块 (rename.js)

| --prefix | -p | 字符串 | 自定义前缀,默认P |
| --dir | -d | 无 | 递归处理子目录 |
| --number | -num | 数字 | 序号位数,默认5位 |
| --type | -type | <types...> | 文件类型,支持多个类型,如: jpg png gif,不区分大小写,jpg和jpeg视为同一类型 |
| --forceDir | 无 | 无 | 强制重命名文件夹,从1开始自增,先处理子目录再处理父目录 |

@@ -54,21 +58,90 @@ ## 5. 使用示例

### 5.3 按文件类型重命名
```bash
daji rn -p p -type jpg
```
执行此命令后,工具会将当前目录下的所有jpg文件按照p00001.jpg、p00002.jpg的格式重命名。
### 5.4 多类型文件重命名
```bash
daji rn -p p -type jpg png gif
```
执行此命令后,工具会将当前目录下的所有jpg、png、gif文件按照p00001.jpg、p00002.png、p00003.gif的格式重命名。
### 5.5 自定义序号位数
```bash
daji rn -p p -num 4
```
执行此命令后,工具会将当前目录下的文件按照p0001、p0002的4位数格式重命名。
### 5.6 递归处理子目录
```bash
daji rn -p p -d -type jpg
```
执行此命令后,工具会递归处理当前目录及其子目录下的所有jpg文件,每个目录内的文件从p00001.jpg开始编号。
### 5.7 结合多个选项
```bash
daji rn -p p -d -type jpg png -num 4
```
执行此命令后,工具会递归处理当前目录及其子目录下的所有jpg、png文件,每个目录内的文件从p0001.jpg开始编号(4位数)。
### 5.8 重命名文件夹
```bash
daji rn -forceDir
```
执行此命令后,工具会将当前目录下的文件夹按照1、2、3的格式重命名,先处理子目录再处理父目录。
### 5.9 结合文件和文件夹重命名
```bash
daji rn -p p -type jpg -forceDir
```
执行此命令后,工具会同时重命名当前目录下的jpg文件和文件夹,文件按p00001.jpg格式,文件夹按1、2、3格式。
## 6. 实现原理
1. **获取文件列表**:
- 读取当前目录下的所有文件
- 过滤出文件,排除目录
- 按文件名排序
1. **获取文件和文件夹列表**:
- 读取当前目录下的所有文件和文件夹
- 如果指定了 `-d` 选项,则递归处理子目录
- 分别收集文件和文件夹列表
2. **构建新文件名**:
2. **文件类型过滤**:
- 如果指定了 `-type` 选项,按类型过滤文件
- 统一转换为小写,jpg和jpeg视为同一类型
- 不区分文件类型的大小写
3. **构建新文件名**:
- 使用指定前缀(默认P)
- 生成5位递增序号(不足补零)
- 生成指定位数的递增序号(默认5位,不足补零)
- 保留原文件的扩展名
3. **执行重命名**:
- 遍历文件列表
- 逐个执行重命名操作
- 输出重命名结果
4. **执行文件重命名**:
- 按目录分组文件
- 每个目录内的文件独立编号
- 按文件名排序后逐个执行重命名
- 输出重命名过程
4. **统计结果**:
5. **执行文件夹重命名**:
- 如果指定了 `-forceDir` 选项,重命名文件夹
- 按路径长度排序,确保先处理子目录
- 文件夹名称从1开始自增
- 输出重命名过程
6. **统计结果**:
- 统计成功和失败的文件数量
- 统计成功和失败的文件夹数量
- 输出最终结果

@@ -75,0 +148,0 @@

@@ -8,2 +8,163 @@ const fs = require('fs').promises;

/**
* 递归获取目录下的所有文件和文件夹
* @param {string} dirPath - 目录路径
* @param {boolean} recursive - 是否递归处理子目录
* @returns {Promise<Object>} 包含文件和文件夹的对象
*/
async function getAllFilesAndDirs(dirPath, recursive) {
const entries = await fs.readdir(dirPath, { withFileTypes: true });
let result = {
files: [],
dirs: []
};
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
result.dirs.push(fullPath);
if (recursive) {
const subResult = await getAllFilesAndDirs(fullPath, recursive);
result.files = [...result.files, ...subResult.files];
result.dirs = [...result.dirs, ...subResult.dirs];
}
} else {
result.files.push(fullPath);
}
}
return result;
}
/**
* 按目录分组文件
* @param {string[]} filePaths - 文件路径列表
* @returns {Object} 按目录分组的文件
*/
function groupFilesByDir(filePaths) {
const groups = {};
for (const filePath of filePaths) {
const dir = path.dirname(filePath);
if (!groups[dir]) {
groups[dir] = [];
}
groups[dir].push(filePath);
}
return groups;
}
/**
* 重命名文件或文件夹
* @param {string} oldPath - 原路径
* @param {string} newPath - 新路径
* @returns {Promise<boolean>} 重命名是否成功
*/
async function renameItem(oldPath, newPath) {
try {
await fs.rename(oldPath, newPath);
log.success(`${path.basename(oldPath)} → ${path.basename(newPath)}`);
return true;
} catch (error) {
log.error(`重命名 ${path.basename(oldPath)} 失败: ${error.message}`);
return false;
}
}
/**
* 重命名目录下的文件
* @param {string} dirPath - 目录路径
* @param {string[]} filePaths - 该目录下的文件路径
* @param {Object} options - 命令选项
* @returns {Promise<Object>} 重命名结果
*/
async function renameFilesInDir(dirPath, filePaths, options) {
const { prefix = 'P', number = 5 } = options;
// 按文件名排序
const sortedFiles = filePaths.sort();
if (sortedFiles.length === 0) {
log.tip(`${dirPath} 目录下没有需要重命名的文件`);
return { success: 0, fail: 0 };
}
log.info(`\n处理目录: ${dirPath}`);
log.info(`找到 ${sortedFiles.length} 个文件,准备重命名...`);
let successCount = 0;
let failCount = 0;
// 开始重命名
for (let i = 0; i < sortedFiles.length; i++) {
const oldPath = sortedFiles[i];
const ext = path.extname(oldPath);
const newName = `${prefix}${String(i + 1).padStart(number, '0')}${ext}`;
const newPath = path.join(dirPath, newName);
if (await renameItem(oldPath, newPath)) {
successCount++;
} else {
failCount++;
}
}
return { success: successCount, fail: failCount };
}
/**
* 重命名文件夹
* @param {string[]} dirPaths - 文件夹路径列表
* @returns {Promise<Object>} 重命名结果
*/
async function renameDirs(dirPaths) {
// 按路径长度排序,确保先处理子目录
const sortedDirs = dirPaths.sort((a, b) => b.split(path.sep).length - a.split(path.sep).length);
let successCount = 0;
let failCount = 0;
log.info(`\n准备重命名 ${sortedDirs.length} 个文件夹...`);
for (let i = 0; i < sortedDirs.length; i++) {
const oldPath = sortedDirs[i];
const parentDir = path.dirname(oldPath);
const newName = String(i + 1);
const newPath = path.join(parentDir, newName);
if (await renameItem(oldPath, newPath)) {
successCount++;
} else {
failCount++;
}
}
return { success: successCount, fail: failCount };
}
/**
* 过滤文件类型
* @param {string[]} filePaths - 文件路径列表
* @param {string[]} types - 文件类型数组
* @returns {string[]} 过滤后的文件路径
*/
function filterFilesByType(filePaths, types) {
if (!types || types.length === 0) {
return filePaths;
}
// 处理类型:统一转为小写,合并jpg和jpeg
const normalizedTypes = types.map(type => {
const lowerType = type.toLowerCase();
return lowerType === 'jpeg' ? 'jpg' : lowerType;
});
return filePaths.filter(filePath => {
const ext = path.extname(filePath).toLowerCase().replace('.', '');
const normalizedExt = ext === 'jpeg' ? 'jpg' : ext;
return normalizedTypes.includes(normalizedExt);
});
}
/**
* 重命名当前目录下的文件

@@ -14,3 +175,9 @@ * @param {string} cmd - 命令参数

async function renameTools(cmd, options) {
const { prefix = 'P' } = options;
const {
prefix = 'P',
dir: recursive = false,
number = 5,
type: types = [],
forceDir = false
} = options;

@@ -20,42 +187,48 @@ try {

const currentDir = process.cwd();
log.info(`当前目录: ${currentDir}`);
log.info(`当前工作目录: ${currentDir}`);
// 获取当前目录下的所有文件
const files = await fs.readdir(currentDir, { withFileTypes: true });
// 显示处理的文件类型
if (types && types.length > 0) {
log.info(`只处理以下类型的文件: ${types.join(', ')}`);
}
// 过滤出文件(排除目录)
const fileList = files
.filter(file => file.isFile())
.map(file => file.name)
.sort(); // 按文件名排序
// 获取所有文件和文件夹
const allItems = await getAllFilesAndDirs(currentDir, recursive);
if (fileList.length === 0) {
log.tip('当前目录下没有文件需要重命名');
// 过滤文件类型
const filteredFiles = filterFilesByType(allItems.files, types);
if (filteredFiles.length === 0 && !forceDir) {
log.tip('没有找到符合条件的文件需要重命名');
return;
}
log.info(`找到 ${fileList.length} 个文件,准备重命名...`);
// 按目录分组文件
const filesByDir = groupFilesByDir(filteredFiles);
console.log('==============================');
// 开始重命名
let successCount = 0;
let failCount = 0;
// 开始重命名文件
let totalSuccess = 0;
let totalFail = 0;
for (let i = 0; i < fileList.length; i++) {
const oldName = fileList[i];
const ext = path.extname(oldName);
const newName = `${prefix}${String(i + 1).padStart(5, '0')}${ext}`;
if (filteredFiles.length > 0) {
log.info(`找到 ${filteredFiles.length} 个文件,分布在 ${Object.keys(filesByDir).length} 个目录中`);
try {
await fs.rename(path.join(currentDir, oldName), path.join(currentDir, newName));
log.success(`${oldName} → ${newName}`);
successCount++;
} catch (error) {
log.error(`重命名 ${oldName} 失败: ${error.message}`);
failCount++;
for (const [dirPath, filePaths] of Object.entries(filesByDir)) {
const result = await renameFilesInDir(dirPath, filePaths, options);
totalSuccess += result.success;
totalFail += result.fail;
}
}
// 重命名文件夹
if (forceDir && allItems.dirs.length > 0) {
const dirResult = await renameDirs(allItems.dirs);
totalSuccess += dirResult.success;
totalFail += dirResult.fail;
}
console.log('==============================');
log.info(`重命名完成!成功: ${successCount} 个,失败: ${failCount} 个`);
log.info(`重命名完成!总成功: ${totalSuccess} 个,总失败: ${totalFail} 个`);

@@ -62,0 +235,0 @@ } catch (error) {

+1
-1
{
"name": "daji",
"version": "2.0.1",
"version": "2.0.2",
"description": "",

@@ -5,0 +5,0 @@ "main": "index.js",