init
This commit is contained in:
commit
ebe81223d8
|
|
@ -0,0 +1,3 @@
|
|||
/node_modules
|
||||
/in
|
||||
/out
|
||||
|
|
@ -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
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
@ -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"]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue