zoukankan      html  css  js  c++  java
  • NodeJs 批量重命名文件,并保存到指定目录

    源代码(file-rename.js)

    // 文件路径:file-rename.js
    /**
     * NodeJs 批量重命名文件,并保存到指定目录,支持递归目录
     * 功能:批量重命名文件,并保存到指定目录,支持递归目录
     * 使用:node file-rename.js
     * 扩展包:无
     */
    
    // 引用 fs 文件系统模块
    const NmFs = require('fs');
    // 引用 path 路径处理模块
    const NmPath = require('path');
    
    // 配置信息
    const config = {
        // 过滤字符串模式
        filter_text: {
            enable: false,
            text: '',
        },
        // 前面删除模式
        trim_start: {
            enable: true,
            // 删除指定的字符串
            text: '',
            // 删除 {length} 个字符
            length: 10,
            // 删除 {length} 必须包含的关键词
            length_key: 'NO.',
        },
        // 后面删除模式
        trim_end: {
            enable: false,
            // 删除指定的字符串
            text: '',
            // 删除 {length} 个字符
            length: 0
        },
        // 后面追加模式
        append: {
            enable: false,
            text: '-append',
        },
        // 前面追加件模式
        prepend: {
            enable: false,
            text: 'prepend-',
        },
        // 中间替换或插入模式
        splice: {
            enable: false,
            // 删除的开始位置
            start: 0,
            // 被删除的字符数量,数值 0 表示插入字符串
            length: 0,
            // 要替换或插入的字符串
            text: '',
        },
        // 允许处理的文件扩展名
        allow_exts: {
            enable: false,
            exts: ['jpg', 'png', 'gif', 'jpeg', 'webp', 'tiff'],
        },
        // 跳过处理的文件扩展名
        skip_exts: {
            enable: false,
            exts: []
        }
    }
    
    /**
     * 更改文件名
     * @param {String} basename 文件名,无扩展名
     * @param {String} ext 文件扩展名
     */
    function changeName(basename = '', ext = '', isDirMode = false) {
        if (!isDirMode && ext) {
            if ((config.allow_exts.enable && !config.allow_exts.exts.includes(ext))) {
                return basename;
            }
            if (config.skip_exts.enable && config.skip_exts.exts.includes(ext)) {
                return basename;
            }
        }
        let nameLength = basename.length;
        // 文件名前面移除字符
        if (config.trim_start.enable) {
            // 字符串匹配删除模式
            if (config.trim_start.text.length > 0 && basename.indexOf(config.trim_start.text) > -1) {
                // basename = basename.substring(config.trim_start.text.length);
                basename = basename.replace(config.trim_start.text, '');
            }
            // 字符长度删除模式
            if (config.trim_start.length > 0 && (nameLength > config.trim_start.length)) {
                console.log(basename, config.trim_start.length_key, basename.indexOf(config.trim_start.length_key));
                if ((config.trim_start.length_key.length == 0) || (config.trim_start.length_key.length > 0 && basename.indexOf(config.trim_start.length_key) > 0)) {
                    basename = basename.substring(config.trim_start.length);
                }
            }
        }
        // 文件名后面移除字符
        if (config.trim_end.enable) {
            // 字符串匹配删除模式
            if (basename.indexOf(config.trim_end.text) > -1) {
                // basename = basename.substring(0, nameLength - config.trim_end.text.length);
                basename = basename.replace(config.trim_end.text, '');
            }
            // 字符长度删除模式
            if (config.trim_end.length > 0 && nameLength > config.trim_end.length) {
                basename = basename.substring(0, nameLength - config.trim_end.length);
            }
        }
        // 过滤字符串模式
        if (config.filter_text.enable && config.filter_text.text.length > 0) {
            basename = basename.replace(new RegExp(config.filter_text.text, 'ig'), '');
        }
        // 中间替换或插入模式
        if (config.splice.enable) {
            let a = basename.substring(0, config.splice.start);
            let b = basename.substring(config.splice.start + config.splice.length);
            basename = a + config.splice.text + b;
        }
        // 文件名前面插入字符
        if (config.prepend.enable) {
            basename = config.prepend.text + basename;
        }
        // 文件名后面插入字符
        if (config.append.enable) {
            basename = basename + config.append.text;
        }
        return basename;
    }
    
    /**
     * 批量更改文件名到指定目录
     * @param {String} fromDir 来源目录
     * @param {String} toDir 目标目录
     * @param {Boolean} isDebug 是否调试模式。调试模式不会执行重命名操作,只会输出控制台日志
     * @param {Boolean} isSkipExists 是否跳过已存在的目标文件
     * @param {Boolean} isDirMode 是否重命名对象为目录,否则为文件
     * @param {Boolean} isRecursion 是否递归遍历子目录
     */
    async function renameFiles(fromDir, toDir, isDebug = true, isSkipExists = true, isDirMode = false, isRecursion = true) {
        if (!NmFs.existsSync(fromDir)) {
            console.log('path not exists: ', fromDir);
            return;
        }
        // 自动创建目标路径
        if (!isDebug && !NmFs.existsSync(toDir)) {
            NmFs.mkdirSync(toDir, {
                recursive: true
            });
        }
        let sep = NmPath.sep;
        // 自动补齐路径符
        if (!fromDir.endsWith(sep)) {
            fromDir += sep;
        }
        if (!toDir.endsWith(sep)) {
            toDir += sep;
        }
        // 打开目录
        const dir = await NmFs.promises.opendir(fromDir);
        // 声明变量,优化内存
        let basename = '',
            ext = '',
            newPath = '',
            currentPath = '';
        for await (const dirent of dir) {
            // 当前路径
            currentPath = fromDir + dirent.name;
            newPath = toDir + dirent.name;
            // 处理目录
            if (dirent.isDirectory()) {
                // 如果当前路径是目录,则进入递归模式
                if (isDirMode) {
                    ext = '';
                    basename = NmPath.basename(dirent.name, ext); // 无扩展名
                    basename = changeName(basename, ext);
                    newPath = toDir + basename;
                    // 判断是否过滤已存在的目标文件
                    if (isSkipExists && NmFs.existsSync(newPath)) {
                        console.log('[已存在]', currentPath, '=>', newPath);
                        continue;
                    }
                    if (!isDebug) {
                        NmFs.renameSync(currentPath, newPath);
                    }
                    console.log('[重命名]', currentPath, '=>', newPath);
                }
                if (isRecursion) {
                    renameFiles(currentPath + sep, newPath + sep, isDebug, isSkipExists, isDirMode, isRecursion);
                }
                continue;
            }
            if (isDirMode) {
                continue;
            }
            // 文件名
            ext = NmPath.extname(dirent.name); // .jpg
            basename = NmPath.basename(dirent.name, ext); // 无扩展名
            ext = ext.substring(1).toLowerCase();
            basename = changeName(basename, ext);
            newPath = toDir + basename + '.' + ext;
            // 判断是否过滤已存在的目标文件
            if (isSkipExists && NmFs.existsSync(newPath)) {
                console.log('[已存在]', currentPath, '=>', newPath);
                continue;
            }
            if (!isDebug) {
                NmFs.renameSync(currentPath, newPath);
            }
            console.log('[重命名]', currentPath, '=>', newPath);
        }
    }
    
    // 执行批量文件重命名功能
    const FROM_DIR = 'F:\Downloads\Images';
    const TO_DIR = FROM_DIR;
    const IS_DEBUG = false;
    const IS_SKIP_EXISTS = true;
    const IS_DIR_MODE = true;
    const IS_RECURSION = false;
    renameFiles(FROM_DIR, TO_DIR, IS_DEBUG, IS_SKIP_EXISTS, IS_DIR_MODE, IS_RECURSION).catch(err => console.log(err))
    

    运行文件

    node file-rename.js
    
  • 相关阅读:
    详解并发和并行意义
    MoleHill Getting Started AGAL(转)
    解决setInterval计时器不准的问题
    Flash视频播放器开发经验总结
    利用pushState开发无刷页面切换
    用小乐图客抓取人人网照片
    如何在Flash中新窗口打开页面而不被拦截
    响应式开发总结
    用Asroute解决复杂状态切换问题
    对iframe跨域通信的封装
  • 原文地址:https://www.cnblogs.com/sochishun/p/14290072.html
Copyright © 2011-2022 走看看