zoukankan      html  css  js  c++  java
  • NodeJS二进制合并

    Node.js 批量文件合并code

    cnblogs @ Orcim   



     文主要介绍使用 Node 进行 ACB 序列文件(Atom CueSheet Binary,编译 AtomCueSheet 二进制文件)进行合并的方法。

    ACB 文件

    ACB文件是日本一家叫做 CRI Middleware 的公司开发的音频包文件,包含ADX或ADX2格式的音频流。主要用于游戏中的声音特效以及背景音乐。其广泛用于 Unity 开发的各种游戏之中,游戏厂商将音频转换为这种二进制的音频文件,再将其打包成 Unity 的资源包(Assets),也就是游戏的资源更新包。而游戏厂商有时将一个 ACB 文件分割成多个二进制文件,这样就需要将其先合并。

    ACB文件可以用 CRI Atom Craft 进行查看以及编辑,当然,这个软件也是由这家公司所开发。

    关于ACB文件以及ADX2的更多详情,参见官方文档。感觉这种音频文件挺有趣的。

    对于我为什么想写此篇博文,以及我为什么要用Node来做ACB文件合并这件事,只是因为偶然在提取游戏资源时碰到了ACB音频文件(起初我还并不知道这是音频流)没事干,折腾了一下,撰文记录我一个晚上的研究成果。

    以上是这类二进制音频流文件的科普,以下正文。

    ACB文件序列一览

    下图是我用UnityStudio_x64从某个游戏中的Assets文件中提取出来的ACB源文件:

     

    一段 BGM 被分割成了总共 41 个文件,提取出来的文件后缀是 .txt,文件是二进制的,用记事本打开会乱码。需要将这些文件合并成一个 ACB 文件。文件名是按规律来排列的:bgm133-[ Number ].acb.txt

    思路

    1)首先先读取这些 .acb.txt 文件的二进制数据,因为文件有按照数字编号排列,所以要按顺序进行读取并合并。

    2)接下来就是进行读文件的操作,得到文件的 Buffer,一个类数组的数据

    3)然后将这些文件的 Buffer 合并,这一步类似于多个数组进行 concat 的操作

    4)最后一步依据合并得到的数组创建一个 Buffer 对象,例:_buf_,NodeJs 中是用 var buf = Buffer.from( _buf_ ),再写文件 fs.writeFileSync("unite.acb", buf)

    方案实施

    具体流程,详见代码 unite.JS:

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
    var t0 = new Date().valueOf();
    const fs = require("fs");
    const path = require("path");
    const join = path.join;
     
    var fNames = getFileNames(__dirname); // 获取当前文件夹
    var base = fNames.map(function(itemidx){
        return path.basename(item); // 当前目录下所有文件路径
    });
    var baseFiles = []; // 用于存储 CAB 文件的文件名队列
    for(var _=0_<base.length; _++){
        if(!path.basename(base[_]).match(/.acb.txt/)) continue// 判断文件名符不符合 *.acb.txt
        baseFiles.push(base[_]); // 如果符合就 push 到队列之中
    }
    console.log(baseFiles); // ["..001.acb.txt", "..002.acb.txt", ..., "..041.acb.txt"]
    var buf = [], a = 0// var( buf ) -> 用于存储合并后文件的二进制值数组
    baseFiles.forEach(function(itemidx){
        var pos_center = item.indexOf("-")+1// 从 ..001.acb.txt 开始
        // 按照 001 ~ 041 的文件名顺序进行 Buffer 的连接
        var tmpBuf = fs.readFileSync(path.join(__dirname, item.substr(0pos_center+ to3digit(idx+1+ ".acb.txt"));
        var tmpLength = tmpBuf.length;
        for(var b=0b<tmpLengthb++){
            buf[a= tmpBuf[b]; // 类似于数组的 concat 操作
            a++;
        }
    });
    fs.writeFileSync(__dirname + "\unite.acb"Buffer.from(buf));
    function getFileNames(_path){ // 获取当前目录下所有文件的路径数组
        let jsonFiles = [];
        function findJsonFile(path){
            let files = fs.readdirSync(path);
            files.forEach(function(item){
                let fPath = join(pathitem);
                let stat = fs.statSync(fPath);
                if(stat.isDirectory() === true){
                    findJsonFile(fPath);
                }
                if(stat.isFile() === true){
                    jsonFiles.push(fPath);
                }
            });
        }
        findJsonFile(_path);
        return jsonFiles;
    }
    function to3digit(num){ // 数字转换为三位的字符串,数字不足三位补0
        return (num<10?"00":(num<100?"0":"")) + num;
    }
    // console.log(to3digit(1), to3digit(9), to3digit(10), to3digit(99), to3digit(100), to3digit(999), to3digit(1000))
    console.info("Bundled x1B[35m%dx1B[39m file%s in x1B[32m%dmsx1B[39m"baseFiles.length, baseFiles.length>1?"s":""new Date().valueOf() - t0);
     

    使用方法

    1. 将unite.js放在ACB序列文件所在的根目录下

    2. 打开命令行工具,运行 unite.js:可以将js文件直接拖到命令行窗口中运行。

    3. 合并成功

    4. 合并后目录下会合并写好一个unite.acb文件,文件可以通过 VGMToolbox 工具进行提取,转换为 .hca 音频,foobar2000 安装 VGMStream Decoder 插件后(点击下载,解压后双击安装),即可播放 .hca 音频或进行格式转换

       

    结束语

    使用工具:NodeJS、UnityStudio、VGMToolbox、foobar2000、VGMStream Decoder

  • 相关阅读:
    js操作
    函数知识点补充
    css---position
    css-浮动
    css-边界重叠以及边界塌陷
    css
    css文本类型操作
    POJ 2828 线段树活用
    POJ 3468 线段树
    POJ 3013 SPFA算法,邻接表的使用
  • 原文地址:https://www.cnblogs.com/Orcim/p/10690562.html
Copyright © 2011-2022 走看看