commit ebe81223d866c5528651e80da78d10dd475d0c82 Author: pqcqaq <905739777@qq.com> Date: Wed Jan 15 20:20:21 2025 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0050a28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/in +/out \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..f5acaa3 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,222 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const child_process_1 = require("child_process"); +const adm_zip_1 = __importDefault(require("adm-zip")); +const DISALLOWED_EXTENSIONS = new Set([ + ".exe", + ".o", + ".class", + ".bin", + ".dll", + ".vcxproj", + ".filters", + ".user", + ".sln", +]); +const DISALLOWED_KEYWORDS = new Set(["a.out", "main", "temp"]); +const DISALLOWED_DIRECTORIES = new Set([ + ".vs", + ".idea", + "__pycache__", + "node_modules", + ".git", + "x64", + "x86", + "__MACOSX", + ".vscode", +]); +let deletedItems = []; +// 清理文件名 +const sanitizeFileName = (fileName) => { + // 对文件名进行标准化处理,解决编码问题 + const decodedName = fileName.toString("utf8"); + return decodedName; +}; +// 检查是否是压缩文件 +const isCompressedFile = (filePath) => { + return (filePath.endsWith(".zip") || + filePath.endsWith(".7z") || + filePath.endsWith(".rar")); +}; +// 测试是否安装了7z和unrar +const preTest = () => { + try { + (0, child_process_1.execSync)("7z --help"); + } + catch (e) { + console.error("[ERROR] 7z 未安装,请先安装 7z。"); + process.exit(1); + } + try { + (0, child_process_1.execSync)("unrar"); + } + catch (e) { + console.error("[ERROR] unrar 未安装,请先安装 unrar。"); + process.exit(1); + } +}; +// 检查文件是否可能是Linux可执行文件(无后缀的二进制) +const isLinuxExecutable = (filePath) => { + if (fs_1.default.statSync(filePath).isFile() && path_1.default.extname(filePath) === "") { + const stats = fs_1.default.statSync(filePath); + return (stats.mode & 0o111) !== 0; + } + return false; +}; +// 使用7z解压文件 +const extractUsing7z = (filePath, extractTo) => { + console.log(`[INFO] 使用 7z 解压文件: ${filePath} 到目录: ${extractTo}`); + if (!fs_1.default.existsSync(extractTo)) { + fs_1.default.mkdirSync(extractTo, { recursive: true }); + } + try { + (0, child_process_1.execSync)(`7z x "${filePath}" -o"${extractTo}"`); + console.log(`[INFO] 解压完成: ${filePath}`); + } + catch (e) { + console.error(`[ERROR] 解压失败: ${e}`); + } +}; +// 使用unrar解压文件 +const extractRar = (filePath, extractTo) => { + console.log(`[INFO] 使用 unrar 解压文件: ${filePath} 到目录: ${extractTo}`); + if (!fs_1.default.existsSync(extractTo)) { + fs_1.default.mkdirSync(extractTo, { recursive: true }); + } + try { + (0, child_process_1.execSync)(`unrar x -o+ "${filePath}" "${extractTo}"`); + console.log(`[INFO] 解压完成: ${filePath}`); + } + catch (e) { + console.error(`[ERROR] 解压失败: ${e}`); + } +}; +/** + * 解压缩文件 + * @param inputDirectory 输入目录 + * @param outputDirectory 输出目录 + * @deprecated 存在编码问题,暂时不使用 + */ +const extractZip = (filePath, extractTo) => { + console.log(`[INFO] 解压缩文件: ${filePath} 到目录: ${extractTo}`); + if (!fs_1.default.existsSync(extractTo)) { + fs_1.default.mkdirSync(extractTo, { recursive: true }); + } + const zip = new adm_zip_1.default(filePath); + // 遍历所有的文件条目,清理文件名中的非法字符 + zip.getEntries().forEach((entry) => { + if (entry.entryName) { + try { + // 清理文件名中的非法字符 + const sanitizedName = sanitizeFileName(entry.rawEntryName); + entry.entryName = sanitizedName; // 更新文件名 + } + catch (e) { + console.error(`[ERROR] 解压时处理文件名失败: ${entry.entryName}`); + } + } + }); + // 解压文件 + zip.extractAllTo(extractTo, true); +}; +// 递归处理目录并过滤文件 +const processDirectory = (inputDirectory, outputDirectory) => { + console.log(`[INFO] 开始处理目录: ${inputDirectory}`); + fs_1.default.readdirSync(inputDirectory).forEach((item) => { + const itemPath = path_1.default.join(inputDirectory, item); + const stat = fs_1.default.statSync(itemPath); + if (stat.isDirectory()) { + // 排除不需要的目录 + if (DISALLOWED_DIRECTORIES.has(item)) { + deletedItems.push(`目录: ${itemPath}`); + fs_1.default.rmdirSync(itemPath, { recursive: true }); + console.log(`[DELETE] 删除目录: ${itemPath}`); + } + else { + // 创建对应的输出目录 + const outputDirPath = path_1.default.join(outputDirectory, item); + if (!fs_1.default.existsSync(outputDirPath)) { + fs_1.default.mkdirSync(outputDirPath, { recursive: true }); + } + processDirectory(itemPath, outputDirPath); // 递归处理子目录 + } + } + else if (stat.isFile()) { + const ext = path_1.default.extname(item).toLowerCase(); + // 如果是压缩文件,解压后递归处理 + if (isCompressedFile(itemPath)) { + const relativePath = path_1.default.relative(inputDirectory, path_1.default.dirname(itemPath)); + const outputDirPath = path_1.default.join(outputDirectory, relativePath, path_1.default.basename(itemPath, path_1.default.extname(itemPath)) + + "_extracted"); + if (!fs_1.default.existsSync(outputDirPath)) { + fs_1.default.mkdirSync(outputDirPath, { recursive: true }); + } + if (itemPath.endsWith(".zip")) { + // extractZip(itemPath, outputDirPath); // 存在编码问题,暂时不使用 + extractUsing7z(itemPath, outputDirPath); + } + else if (itemPath.endsWith(".7z")) { + extractUsing7z(itemPath, outputDirPath); + } + else if (itemPath.endsWith(".rar")) { + extractRar(itemPath, outputDirPath); + } + // 递归处理解压后的内容 + processDirectory(outputDirPath, outputDirPath); + // 重新压缩处理后的内容 + const outputZip = path_1.default.join(outputDirectory, relativePath, path_1.default.basename(itemPath)); + const zip = new adm_zip_1.default(); + zip.addLocalFolder(outputDirPath); + zip.writeZip(outputZip); + // 删除临时目录 + console.log(`[DELETE] 删除临时目录: ${outputDirPath}`); + fs_1.default.rmSync(outputDirPath, { recursive: true, force: true }); + } + else if (DISALLOWED_EXTENSIONS.has(ext) || + DISALLOWED_KEYWORDS.has(item) || + isLinuxExecutable(itemPath)) { + console.log(`[DELETE] 删除文件: ${itemPath}`); + deletedItems.push(`文件: ${itemPath}`); + fs_1.default.rmSync(itemPath); // 删除不需要的文件 + } + else { + // 将文件复制到对应的输出目录 + const outputFilePath = path_1.default.join(outputDirectory, item); + fs_1.default.copyFileSync(itemPath, outputFilePath); + console.log(`[KEEP] 保留文件: ${itemPath} 并复制到 ${outputFilePath}`); + } + } + }); +}; +// 写入统计文件 +const writeLog = (outputDirectory) => { + const logFile = path_1.default.join(outputDirectory, "result_log.txt"); + fs_1.default.writeFileSync(logFile, "以下是被删除的目录和文件列表:\n"); + fs_1.default.appendFileSync(logFile, deletedItems.join("\n")); + console.log(`[INFO] 统计文件已生成: ${logFile}`); +}; +// 主函数 +const main = () => { + preTest(); // 测试是否安装了7z和unrar + const inputDirectory = path_1.default.join(process.cwd(), "in"); // 输入文件夹 + const outputDirectory = path_1.default.join(process.cwd(), "out"); // 输出文件夹 + if (!fs_1.default.existsSync(inputDirectory)) { + console.error(`[ERROR] 输入目录 'in' 不存在,请检查。`); + return; + } + if (fs_1.default.existsSync(outputDirectory)) { + fs_1.default.rmSync(outputDirectory, { recursive: true }); // 清空输出目录 + } + fs_1.default.mkdirSync(outputDirectory, { recursive: true }); + console.log("[INFO] 开始处理压缩文件..."); + processDirectory(inputDirectory, outputDirectory); + writeLog(outputDirectory); + console.log('[INFO] 处理完成!结果保存在 "out" 目录中。'); +}; +main(); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/index.js.map b/lib/index.js.map new file mode 100644 index 0000000..22ada01 --- /dev/null +++ b/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/process_zip_files.js b/lib/process_zip_files.js new file mode 100644 index 0000000..0699eaf --- /dev/null +++ b/lib/process_zip_files.js @@ -0,0 +1,222 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const child_process_1 = require("child_process"); +const adm_zip_1 = __importDefault(require("adm-zip")); +const DISALLOWED_EXTENSIONS = new Set([ + ".exe", + ".o", + ".class", + ".bin", + ".dll", + ".vcxproj", + ".filters", + ".user", + ".sln", +]); +const DISALLOWED_KEYWORDS = new Set(["a.out", "main", "temp"]); +const DISALLOWED_DIRECTORIES = new Set([ + ".vs", + ".idea", + "__pycache__", + "node_modules", + ".git", + "x64", + "x86", + "__MACOSX", + ".vscode", +]); +let deletedItems = []; +// 清理文件名 +const sanitizeFileName = (fileName) => { + // 对文件名进行标准化处理,解决编码问题 + const decodedName = fileName.toString("utf8"); + return decodedName; +}; +// 检查是否是压缩文件 +const isCompressedFile = (filePath) => { + return (filePath.endsWith(".zip") || + filePath.endsWith(".7z") || + filePath.endsWith(".rar")); +}; +// 测试是否安装了7z和unrar +const preTest = () => { + try { + (0, child_process_1.execSync)("7z --help"); + } + catch (e) { + console.error("[ERROR] 7z 未安装,请先安装 7z。"); + process.exit(1); + } + try { + (0, child_process_1.execSync)("unrar"); + } + catch (e) { + console.error("[ERROR] unrar 未安装,请先安装 unrar。"); + process.exit(1); + } +}; +// 检查文件是否可能是Linux可执行文件(无后缀的二进制) +const isLinuxExecutable = (filePath) => { + if (fs_1.default.statSync(filePath).isFile() && path_1.default.extname(filePath) === "") { + const stats = fs_1.default.statSync(filePath); + return (stats.mode & 0o111) !== 0; + } + return false; +}; +// 使用7z解压文件 +const extractUsing7z = (filePath, extractTo) => { + console.log(`[INFO] 使用 7z 解压文件: ${filePath} 到目录: ${extractTo}`); + if (!fs_1.default.existsSync(extractTo)) { + fs_1.default.mkdirSync(extractTo, { recursive: true }); + } + try { + (0, child_process_1.execSync)(`7z x "${filePath}" -o"${extractTo}"`); + console.log(`[INFO] 解压完成: ${filePath}`); + } + catch (e) { + console.error(`[ERROR] 解压失败: ${e}`); + } +}; +// 使用unrar解压文件 +const extractRar = (filePath, extractTo) => { + console.log(`[INFO] 使用 unrar 解压文件: ${filePath} 到目录: ${extractTo}`); + if (!fs_1.default.existsSync(extractTo)) { + fs_1.default.mkdirSync(extractTo, { recursive: true }); + } + try { + (0, child_process_1.execSync)(`unrar x -o+ "${filePath}" "${extractTo}"`); + console.log(`[INFO] 解压完成: ${filePath}`); + } + catch (e) { + console.error(`[ERROR] 解压失败: ${e}`); + } +}; +/** + * 解压缩文件 + * @param inputDirectory 输入目录 + * @param outputDirectory 输出目录 + * @deprecated 存在编码问题,暂时不使用 + */ +const extractZip = (filePath, extractTo) => { + console.log(`[INFO] 解压缩文件: ${filePath} 到目录: ${extractTo}`); + if (!fs_1.default.existsSync(extractTo)) { + fs_1.default.mkdirSync(extractTo, { recursive: true }); + } + const zip = new adm_zip_1.default(filePath); + // 遍历所有的文件条目,清理文件名中的非法字符 + zip.getEntries().forEach((entry) => { + if (entry.entryName) { + try { + // 清理文件名中的非法字符 + const sanitizedName = sanitizeFileName(entry.rawEntryName); + entry.entryName = sanitizedName; // 更新文件名 + } + catch (e) { + console.error(`[ERROR] 解压时处理文件名失败: ${entry.entryName}`); + } + } + }); + // 解压文件 + zip.extractAllTo(extractTo, true); +}; +// 递归处理目录并过滤文件 +const processDirectory = (inputDirectory, outputDirectory) => { + console.log(`[INFO] 开始处理目录: ${inputDirectory}`); + fs_1.default.readdirSync(inputDirectory).forEach((item) => { + const itemPath = path_1.default.join(inputDirectory, item); + const stat = fs_1.default.statSync(itemPath); + if (stat.isDirectory()) { + // 排除不需要的目录 + if (DISALLOWED_DIRECTORIES.has(item)) { + deletedItems.push(`目录: ${itemPath}`); + fs_1.default.rmdirSync(itemPath, { recursive: true }); + console.log(`[DELETE] 删除目录: ${itemPath}`); + } + else { + // 创建对应的输出目录 + const outputDirPath = path_1.default.join(outputDirectory, item); + if (!fs_1.default.existsSync(outputDirPath)) { + fs_1.default.mkdirSync(outputDirPath, { recursive: true }); + } + processDirectory(itemPath, outputDirPath); // 递归处理子目录 + } + } + else if (stat.isFile()) { + const ext = path_1.default.extname(item).toLowerCase(); + // 如果是压缩文件,解压后递归处理 + if (isCompressedFile(itemPath)) { + const relativePath = path_1.default.relative(inputDirectory, path_1.default.dirname(itemPath)); + const outputDirPath = path_1.default.join(outputDirectory, relativePath, path_1.default.basename(itemPath, path_1.default.extname(itemPath)) + + "_extracted"); + if (!fs_1.default.existsSync(outputDirPath)) { + fs_1.default.mkdirSync(outputDirPath, { recursive: true }); + } + if (itemPath.endsWith(".zip")) { + // extractZip(itemPath, outputDirPath); // 存在编码问题,暂时不使用 + extractUsing7z(itemPath, outputDirPath); + } + else if (itemPath.endsWith(".7z")) { + extractUsing7z(itemPath, outputDirPath); + } + else if (itemPath.endsWith(".rar")) { + extractRar(itemPath, outputDirPath); + } + // 递归处理解压后的内容 + processDirectory(outputDirPath, outputDirPath); + // 重新压缩处理后的内容 + const outputZip = path_1.default.join(outputDirectory, relativePath, path_1.default.basename(itemPath)); + const zip = new adm_zip_1.default(); + zip.addLocalFolder(outputDirPath); + zip.writeZip(outputZip); + // 删除临时目录 + console.log(`[DELETE] 删除临时目录: ${outputDirPath}`); + fs_1.default.rmSync(outputDirPath, { recursive: true, force: true }); + } + else if (DISALLOWED_EXTENSIONS.has(ext) || + DISALLOWED_KEYWORDS.has(item) || + isLinuxExecutable(itemPath)) { + console.log(`[DELETE] 删除文件: ${itemPath}`); + deletedItems.push(`文件: ${itemPath}`); + fs_1.default.rmSync(itemPath); // 删除不需要的文件 + } + else { + // 将文件复制到对应的输出目录 + const outputFilePath = path_1.default.join(outputDirectory, item); + fs_1.default.copyFileSync(itemPath, outputFilePath); + console.log(`[KEEP] 保留文件: ${itemPath} 并复制到 ${outputFilePath}`); + } + } + }); +}; +// 写入统计文件 +const writeLog = (outputDirectory) => { + const logFile = path_1.default.join(outputDirectory, "result_log.txt"); + fs_1.default.writeFileSync(logFile, "以下是被删除的目录和文件列表:\n"); + fs_1.default.appendFileSync(logFile, deletedItems.join("\n")); + console.log(`[INFO] 统计文件已生成: ${logFile}`); +}; +// 主函数 +const main = () => { + preTest(); // 测试是否安装了7z和unrar + const inputDirectory = path_1.default.join(process.cwd(), "in"); // 输入文件夹 + const outputDirectory = path_1.default.join(process.cwd(), "out"); // 输出文件夹 + if (!fs_1.default.existsSync(inputDirectory)) { + console.error(`[ERROR] 输入目录 'in' 不存在,请检查。`); + return; + } + if (fs_1.default.existsSync(outputDirectory)) { + fs_1.default.rmSync(outputDirectory, { recursive: true }); // 清空输出目录 + } + fs_1.default.mkdirSync(outputDirectory, { recursive: true }); + console.log("[INFO] 开始处理压缩文件..."); + processDirectory(inputDirectory, outputDirectory); + writeLog(outputDirectory); + console.log('[INFO] 处理完成!结果保存在 "out" 目录中。'); +}; +main(); +//# sourceMappingURL=process_zip_files.js.map \ No newline at end of file diff --git a/lib/process_zip_files.js.map b/lib/process_zip_files.js.map new file mode 100644 index 0000000..59be49e --- /dev/null +++ b/lib/process_zip_files.js.map @@ -0,0 +1 @@ +{"version":3,"file":"process_zip_files.js","sourceRoot":"","sources":["../src/process_zip_files.ts"],"names":[],"mappings":";;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,iDAAyC;AACzC,sDAA6B;AAE7B,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACrC,MAAM;IACN,IAAI;IACJ,QAAQ;IACR,MAAM;IACN,MAAM;IACN,UAAU;IACV,UAAU;IACV,OAAO;IACP,MAAM;CACN,CAAC,CAAC;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/D,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACtC,KAAK;IACL,OAAO;IACP,aAAa;IACb,cAAc;IACd,MAAM;IACN,KAAK;IACL,KAAK;IACL,UAAU;IACV,SAAS;CACT,CAAC,CAAC;AACH,IAAI,YAAY,GAAa,EAAE,CAAC;AAEhC,QAAQ;AACR,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAU,EAAE;IACrD,qBAAqB;IACrB,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,WAAW,CAAC;AACpB,CAAC,CAAC;AAEF,YAAY;AACZ,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAW,EAAE;IACtD,OAAO,CACN,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CACzB,CAAC;AACH,CAAC,CAAC;AAEF,kBAAkB;AAClB,MAAM,OAAO,GAAG,GAAG,EAAE;IACpB,IAAI,CAAC;QACJ,IAAA,wBAAQ,EAAC,WAAW,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,CAAC;QACJ,IAAA,wBAAQ,EAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;AACF,CAAC,CAAC;AAEF,+BAA+B;AAC/B,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAW,EAAE;IACvD,IAAI,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,IAAI,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;QACrE,MAAM,KAAK,GAAG,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,WAAW;AACX,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAE,SAAiB,EAAQ,EAAE;IACpE,OAAO,CAAC,GAAG,CAAC,sBAAsB,QAAQ,SAAS,SAAS,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,YAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC;QACJ,IAAA,wBAAQ,EAAC,SAAS,QAAQ,QAAQ,SAAS,GAAG,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACrC,CAAC;AACF,CAAC,CAAC;AAEF,cAAc;AACd,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,SAAiB,EAAQ,EAAE;IAChE,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,SAAS,SAAS,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,YAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC;QACJ,IAAA,wBAAQ,EAAC,gBAAgB,QAAQ,MAAM,SAAS,GAAG,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACrC,CAAC;AACF,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,SAAiB,EAAQ,EAAE;IAChE,OAAO,CAAC,GAAG,CAAC,iBAAiB,QAAQ,SAAS,SAAS,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,YAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,iBAAM,CAAC,QAAQ,CAAC,CAAC;IAEjC,wBAAwB;IACxB,GAAG,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAClC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC;gBACJ,cAAc;gBACd,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;gBAC3D,KAAK,CAAC,SAAS,GAAG,aAAa,CAAC,CAAC,QAAQ;YAC1C,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CACZ,uBAAuB,KAAK,CAAC,SAAS,EAAE,CACxC,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO;IACP,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC,CAAC;AAEF,cAAc;AACd,MAAM,gBAAgB,GAAG,CACxB,cAAsB,EACtB,eAAuB,EAChB,EAAE;IACT,OAAO,CAAC,GAAG,CAAC,kBAAkB,cAAc,EAAE,CAAC,CAAC;IAChD,YAAE,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC/C,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,WAAW;YACX,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,YAAY,CAAC,IAAI,CAAC,OAAO,QAAQ,EAAE,CAAC,CAAC;gBACrC,YAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,kBAAkB,QAAQ,EAAE,CAAC,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBACP,YAAY;gBACZ,MAAM,aAAa,GAAG,cAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;gBACvD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;oBACnC,YAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClD,CAAC;gBACD,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,UAAU;YACtD,CAAC;QACF,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAE7C,kBAAkB;YAClB,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChC,MAAM,YAAY,GAAG,cAAI,CAAC,QAAQ,CACjC,cAAc,EACd,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CACtB,CAAC;gBACF,MAAM,aAAa,GAAG,cAAI,CAAC,IAAI,CAC9B,eAAe,EACf,YAAY,EACZ,cAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;oBAC9C,YAAY,CACb,CAAC;gBAEF,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;oBACnC,YAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClD,CAAC;gBAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC/B,uDAAuD;oBACvD,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;gBACzC,CAAC;qBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBACrC,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;gBACzC,CAAC;qBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBACtC,UAAU,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;gBACrC,CAAC;gBAED,aAAa;gBACb,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;gBAE/C,aAAa;gBACb,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAC1B,eAAe,EACf,YAAY,EACZ,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACvB,CAAC;gBACF,MAAM,GAAG,GAAG,IAAI,iBAAM,EAAE,CAAC;gBACzB,GAAG,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;gBAClC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAExB,SAAS;gBACT,OAAO,CAAC,GAAG,CAAC,oBAAoB,aAAa,EAAE,CAAC,CAAC;gBACjD,YAAE,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,CAAC;iBAAM,IACN,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC;gBAC9B,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC7B,iBAAiB,CAAC,QAAQ,CAAC,EAC1B,CAAC;gBACF,OAAO,CAAC,GAAG,CAAC,kBAAkB,QAAQ,EAAE,CAAC,CAAC;gBAC1C,YAAY,CAAC,IAAI,CAAC,OAAO,QAAQ,EAAE,CAAC,CAAC;gBACrC,YAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;YACjC,CAAC;iBAAM,CAAC;gBACP,gBAAgB;gBAChB,MAAM,cAAc,GAAG,cAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;gBACxD,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;gBAC1C,OAAO,CAAC,GAAG,CACV,gBAAgB,QAAQ,SAAS,cAAc,EAAE,CACjD,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,SAAS;AACT,MAAM,QAAQ,GAAG,CAAC,eAAuB,EAAQ,EAAE;IAClD,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;IAC7D,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IAC/C,YAAE,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM;AACN,MAAM,IAAI,GAAG,GAAS,EAAE;IACvB,OAAO,EAAE,CAAC,CAAC,kBAAkB;IAC7B,MAAM,cAAc,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ;IAC/D,MAAM,eAAe,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ;IAEjE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC5C,OAAO;IACR,CAAC;IAED,IAAI,YAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,YAAE,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;IAC3D,CAAC;IACD,YAAE,CAAC,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,gBAAgB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IAClD,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;AAC7C,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e7b75cb --- /dev/null +++ b/package-lock.json @@ -0,0 +1,69 @@ +{ + "name": "os-exp", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "os-exp", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "adm-zip": "^0.5.16", + "typescript": "^5.6.3" + }, + "devDependencies": { + "@types/adm-zip": "^0.5.7" + } + }, + "node_modules/@types/adm-zip": { + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/@types/adm-zip/-/adm-zip-0.5.7.tgz", + "integrity": "sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.10.6", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.10.6.tgz", + "integrity": "sha512-qNiuwC4ZDAUNcY47xgaSuS92cjf8JbSUoaKS77bmLG1rU7MlATVSiw/IlrjtIyyskXBZ8KkNfjK/P5na7rgXbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmmirror.com/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b7f6989 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "process_zip_files", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "build": "tsc", + "start": "node ./lib/index.js" + }, + "bin": { + "pzf": "./lib/index.js" + }, + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "adm-zip": "^0.5.16", + "typescript": "^5.6.3" + }, + "devDependencies": { + "@types/adm-zip": "^0.5.7" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f7a0f45 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,252 @@ +import fs from "fs"; +import path from "path"; +import { execSync } from "child_process"; +import AdmZip from "adm-zip"; + +const DISALLOWED_EXTENSIONS = new Set([ + ".exe", + ".o", + ".class", + ".bin", + ".dll", + ".vcxproj", + ".filters", + ".user", + ".sln", +]); +const DISALLOWED_KEYWORDS = new Set(["a.out", "main", "temp"]); +const DISALLOWED_DIRECTORIES = new Set([ + ".vs", + ".idea", + "__pycache__", + "node_modules", + ".git", + "x64", + "x86", + "__MACOSX", + ".vscode", +]); +let deletedItems: string[] = []; + +// 清理文件名 +const sanitizeFileName = (fileName: Buffer): string => { + // 对文件名进行标准化处理,解决编码问题 + const decodedName = fileName.toString("utf8"); + return decodedName; +}; + +// 检查是否是压缩文件 +const isCompressedFile = (filePath: string): boolean => { + return ( + filePath.endsWith(".zip") || + filePath.endsWith(".7z") || + filePath.endsWith(".rar") + ); +}; + +// 测试是否安装了7z和unrar +const preTest = () => { + try { + execSync("7z --help"); + } catch (e) { + console.error("[ERROR] 7z 未安装,请先安装 7z。"); + process.exit(1); + } + + try { + execSync("unrar"); + } catch (e) { + console.error("[ERROR] unrar 未安装,请先安装 unrar。"); + process.exit(1); + } +}; + +// 检查文件是否可能是Linux可执行文件(无后缀的二进制) +const isLinuxExecutable = (filePath: string): boolean => { + if (fs.statSync(filePath).isFile() && path.extname(filePath) === "") { + const stats = fs.statSync(filePath); + return (stats.mode & 0o111) !== 0; + } + return false; +}; + +// 使用7z解压文件 +const extractUsing7z = (filePath: string, extractTo: string): void => { + console.log(`[INFO] 使用 7z 解压文件: ${filePath} 到目录: ${extractTo}`); + if (!fs.existsSync(extractTo)) { + fs.mkdirSync(extractTo, { recursive: true }); + } + try { + execSync(`7z x "${filePath}" -o"${extractTo}"`); + console.log(`[INFO] 解压完成: ${filePath}`); + } catch (e) { + console.error(`[ERROR] 解压失败: ${e}`); + } +}; + +// 使用unrar解压文件 +const extractRar = (filePath: string, extractTo: string): void => { + console.log(`[INFO] 使用 unrar 解压文件: ${filePath} 到目录: ${extractTo}`); + if (!fs.existsSync(extractTo)) { + fs.mkdirSync(extractTo, { recursive: true }); + } + try { + execSync(`unrar x -o+ "${filePath}" "${extractTo}"`); + console.log(`[INFO] 解压完成: ${filePath}`); + } catch (e) { + console.error(`[ERROR] 解压失败: ${e}`); + } +}; + +/** + * 解压缩文件 + * @param inputDirectory 输入目录 + * @param outputDirectory 输出目录 + * @deprecated 存在编码问题,暂时不使用 + */ +const extractZip = (filePath: string, extractTo: string): void => { + console.log(`[INFO] 解压缩文件: ${filePath} 到目录: ${extractTo}`); + if (!fs.existsSync(extractTo)) { + fs.mkdirSync(extractTo, { recursive: true }); + } + const zip = new AdmZip(filePath); + + // 遍历所有的文件条目,清理文件名中的非法字符 + zip.getEntries().forEach((entry) => { + if (entry.entryName) { + try { + // 清理文件名中的非法字符 + const sanitizedName = sanitizeFileName(entry.rawEntryName); + entry.entryName = sanitizedName; // 更新文件名 + } catch (e) { + console.error( + `[ERROR] 解压时处理文件名失败: ${entry.entryName}` + ); + } + } + }); + + // 解压文件 + zip.extractAllTo(extractTo, true); +}; + +// 递归处理目录并过滤文件 +const processDirectory = ( + inputDirectory: string, + outputDirectory: string +): void => { + console.log(`[INFO] 开始处理目录: ${inputDirectory}`); + fs.readdirSync(inputDirectory).forEach((item) => { + const itemPath = path.join(inputDirectory, item); + const stat = fs.statSync(itemPath); + + if (stat.isDirectory()) { + // 排除不需要的目录 + if (DISALLOWED_DIRECTORIES.has(item)) { + deletedItems.push(`目录: ${itemPath}`); + fs.rmdirSync(itemPath, { recursive: true }); + console.log(`[DELETE] 删除目录: ${itemPath}`); + } else { + // 创建对应的输出目录 + const outputDirPath = path.join(outputDirectory, item); + if (!fs.existsSync(outputDirPath)) { + fs.mkdirSync(outputDirPath, { recursive: true }); + } + processDirectory(itemPath, outputDirPath); // 递归处理子目录 + } + } else if (stat.isFile()) { + const ext = path.extname(item).toLowerCase(); + + // 如果是压缩文件,解压后递归处理 + if (isCompressedFile(itemPath)) { + const relativePath = path.relative( + inputDirectory, + path.dirname(itemPath) + ); + const outputDirPath = path.join( + outputDirectory, + relativePath, + path.basename(itemPath, path.extname(itemPath)) + + "_extracted" + ); + + if (!fs.existsSync(outputDirPath)) { + fs.mkdirSync(outputDirPath, { recursive: true }); + } + + if (itemPath.endsWith(".zip")) { + // extractZip(itemPath, outputDirPath); // 存在编码问题,暂时不使用 + extractUsing7z(itemPath, outputDirPath); + } else if (itemPath.endsWith(".7z")) { + extractUsing7z(itemPath, outputDirPath); + } else if (itemPath.endsWith(".rar")) { + extractRar(itemPath, outputDirPath); + } + + // 递归处理解压后的内容 + processDirectory(outputDirPath, outputDirPath); + + // 重新压缩处理后的内容 + const outputZip = path.join( + outputDirectory, + relativePath, + path.basename(itemPath) + ); + const zip = new AdmZip(); + zip.addLocalFolder(outputDirPath); + zip.writeZip(outputZip); + + // 删除临时目录 + console.log(`[DELETE] 删除临时目录: ${outputDirPath}`); + fs.rmSync(outputDirPath, { recursive: true, force: true }); + } else if ( + DISALLOWED_EXTENSIONS.has(ext) || + DISALLOWED_KEYWORDS.has(item) || + isLinuxExecutable(itemPath) + ) { + console.log(`[DELETE] 删除文件: ${itemPath}`); + deletedItems.push(`文件: ${itemPath}`); + fs.rmSync(itemPath); // 删除不需要的文件 + } else { + // 将文件复制到对应的输出目录 + const outputFilePath = path.join(outputDirectory, item); + fs.copyFileSync(itemPath, outputFilePath); + console.log( + `[KEEP] 保留文件: ${itemPath} 并复制到 ${outputFilePath}` + ); + } + } + }); +}; + +// 写入统计文件 +const writeLog = (outputDirectory: string): void => { + const logFile = path.join(outputDirectory, "result_log.txt"); + fs.writeFileSync(logFile, "以下是被删除的目录和文件列表:\n"); + fs.appendFileSync(logFile, deletedItems.join("\n")); + console.log(`[INFO] 统计文件已生成: ${logFile}`); +}; + +// 主函数 +const main = (): void => { + preTest(); // 测试是否安装了7z和unrar + const inputDirectory = path.join(process.cwd(), "in"); // 输入文件夹 + const outputDirectory = path.join(process.cwd(), "out"); // 输出文件夹 + + if (!fs.existsSync(inputDirectory)) { + console.error(`[ERROR] 输入目录 'in' 不存在,请检查。`); + return; + } + + if (fs.existsSync(outputDirectory)) { + fs.rmSync(outputDirectory, { recursive: true }); // 清空输出目录 + } + fs.mkdirSync(outputDirectory, { recursive: true }); + + console.log("[INFO] 开始处理压缩文件..."); + processDirectory(inputDirectory, outputDirectory); + writeLog(outputDirectory); + console.log('[INFO] 处理完成!结果保存在 "out" 目录中。'); +}; + +main(); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..67f3f4f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "CommonJS", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./lib", + "rootDir": "./src", + "resolveJsonModule": true, + "sourceMap": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] + } + \ No newline at end of file