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:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
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 ( item idx ){
     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 ( item idx ){
     var   pos_center   =   item . indexOf ( "-" ) + 1 // 從 ..001.acb.txt 開始
     // 按照 001 ~ 041 的文件名順序進行 Buffer 的連接
     var   tmpBuf   =   fs . readFileSync ( path . join (__dirname,  item . substr ( 0 pos_center +   to3digit ( idx + 1 +   ".acb.txt" ));
     var   tmpLength   =   tmpBuf .length;
     for ( var   b = 0 b < tmpLength b ++ ){
         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 ( path item );
             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%d \x1B [39m file%s in  \x1B [32m%dms \x1B [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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM