背景 由於公司的CMS系統里,只接受rar格式壓縮的文件,所以沒法直接使用nodejs里提供的zip壓縮組件。只能從winRar軟體入手了,但網上沒有多少這方面相關的東西,所以下麵也是自己嘗試著在做。 主要解決的幾個問題 rar軟體的位置獲取問題 通過node的命令行組件child_process, ...
背景
由於公司的CMS系統里,只接受rar格式壓縮的文件,所以沒法直接使用nodejs里提供的zip壓縮組件。只能從winRar軟體入手了,但網上沒有多少這方面相關的東西,所以下麵也是自己嘗試著在做。
主要解決的幾個問題
rar軟體的位置獲取問題
通過node的命令行組件child_process,運行註冊表查詢命令REG query ‘鍵值名’,可以查找出相關軟體的目錄,然後使用正則表達式對結果進行匹配,返回軟體目錄。命令如下:
var cp=require('child_process');
cp.exec("reg query HKEY_CLASSES_ROOT\\WinRAR\\shell\\open\\command /ve", function(e, stdout, stderr) {
if(!e){
var str = stdout.match(/\"([^\"]+)\"/)[0];
if(str){
console.log('已經找到winRar程式,詳細地址為:'+str);}else{
console.log('沒有找到winRar程式,無法完成壓縮功能!');
}
}
});
通過上面的命令可以獲取到註冊表中winRar程式的絕對路徑,如果你安裝正確應該獲得下麵這個結果
環境變數設置問題
通過上面一步可以解決winRar軟體的路徑問題,但怎麼才能方便地調用rar命令呢?我的第一個想法就是設置環境變數。通過運行命令行命令set path=%path%;新目錄,node命令如下:
cp.exec("set path=%path%"+";c:\\", function(e, stdout, stderr) {
if(!e){
console.log("環境變數path添加;c:\\成功!")
}
});
獲取結果如下
到這裡好像沒有問題。其實這裡存在一個問題,這個環境變數設置是臨時的,在命令行關閉時這個環境變數就消失了。
無法在下一次調用命令行時使用,所以到這裡來說,無法再進行下去了。
在調用的過程中,設置環境變數和運行命令是兩個步驟:
cp.exec("set path=%path%"+";c:\\", function(e, stdout, stderr) {
if(!e){
console.log("環境變數path添加;c:\\成功!");
cp.exec('rar a -r f:/build/1.rar f:/xc/gulpfile.js',{encoding:'binary'},function(e,stin,stout){
console.log(e,stin,stout);
});
}
});
下麵的方法運行並不能得到正確的結果。
直接調用winRar程式
解決方法有兩種,一種是笨方法,讓每個使用者,手動去配置環境變數。第二種是直接在命令行使用完整的程式路徑調用。
第一種方法,是最後的一步,實在不行才用這個方法,手動畢竟不是程式員該乾的事。
第二種方法,測試可以使用,運行以下代碼,
cp.exec('"C:\\Program Files\\WinRAR\\WinRAR.exe" a -r f:/build/1.rar f:/xc/gulpfile.js',{encoding:'binary'});
將得到以下結果
這裡需要註意的是當路徑中有空格的時候,可以把整個路徑用引號包起來,不然會導致命令行命令運行失敗。
但這裡必須忍受,下麵這個視窗。
一些擴展
1、在壓縮的過程中,會包含上級文件夾,如何去壓縮只包含文件不包含文件夾的,壓縮包形如下麵的圖示
2、對文件目錄包含的內容進行過濾,並對需要的文件及子文件夾進行壓縮,如文件目錄如下,我只想壓縮裡面的htm,txt文件。
可以通過node的fs組件,然後調用fs.readdirSync()方法,然後對得到的數組進行過濾。
需要註意的問題
1、程式運行路徑中有空格時,別忘記用引號把路徑包上,以及對符號進行轉義。
2、在調用rar壓縮文件時,當過濾掉的目錄中含有和當前目錄相同文件名的文件時,也會把子目錄對應的文件壓縮進來。
在文件結構如下
運行下麵的命令
cp.exec('"C:\\Program Files\\WinRAR\\WinRAR.exe" a -r f:/build/1.rar f:/xc/gulp.js',{encoding:'binary'});
雖然在本目錄下沒有對應的文件,但rar程式會自動,遍歷子文件夾,最後生成如下的壓縮包
因為這個組件文件夾里包含gulp.js文件。這會使上面的過濾出現問題,我還沒解決,還沒想到辦法。
總結
基本上面的功能都完成了,只是構建工具里的一小部分,完成對源文件合併,壓縮,md5後,添加的一個小功能。後面還會找一資料看一下,怎麼解決上面的問題。在這裡哪位大俠有解決辦法,可以評論或私信,非常感謝。
附錄一:winRar命令
配置完,winRar的環境變數,直接運行 rar,可以得到下麵這些個列表
使用示例:
rar a contact.rar contact.dat
如果contact.rar不存在將創建contact.rar文件;如果contact.rar壓縮包中已有contact.ext,將更新壓縮包中的contact.ext
rar a -r -v2000 -sfx vudroid2.rar vudroid2
遞歸壓縮vudroid2目錄下全部文件為 2M 大小分捲自解壓文件(自解壓文件就是壓縮文件中已經包含瞭解壓縮的工具,無需用戶自己安裝解壓縮工具) vudroid2.part1.sfx,vudroid2.part2.rar,vudroid2.part3.rar 等,將命令a換成命令m可將文件壓縮後刪除
rar x contact.rar
用絕對路徑來解壓,如果是rar x contact.rar ~/hehe/,前提是hehe文件夾要存在。就是解壓到當前路徑的hehe目錄下,還有一個是e參數,解釋是加壓到當前目錄下,在ubuntu 10.04我實驗過,rar e和rar x都可以用相對路徑和絕對路徑解壓,這一點我也不知道是為什麼
rar a -pzaba contact1.rar contact.dat
使用密碼 zaba 壓縮contact1.rar文件
附錄二:node的child_process組件
child_process.exec(command, [options], callback) 來源:《Node.js v4.2.4 手冊 & 文檔-child_process》
command
{String} 將要執行的命令,用空格分隔參數options
{Object}cwd
{String} 子進程的當前工作目錄env
{Object} 環境變數鍵值對encoding
{String} 編碼(預設為 'utf8')shell
{String} 運行命令的 shell(UNIX 上預設為 '/bin/sh',Windows 上預設為 'cmd.exe'。該 shell 在 UNIX 上應當接受-c
開關,在 Windows 上應當接受/s /c
開關。在 Windows 中,命令行解析應當相容cmd.exe
。)timeout
{Number} 超時(預設為 0)maxBuffer
{Number} 最大緩衝(預設為 200*1024)killSignal
{String} 結束信號(預設為 'SIGTERM')
callback
{Function} 進程結束時回調並帶上輸出error
{Error}stdout
{Buffer}stderr
{Buffer}
- 返回:ChildProcess 對象
在 shell 中執行一個命令並緩衝輸出。
child = exec('cat *.js bad_file | wc -l',
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
回調參數為 (error, stdout, stderr)
。當成功時,error
會是 null
。當遇到錯誤時,error
會是一個Error
實例,並且 err.code
會是子進程的退出代碼,同時 err.signal
會被設置為結束進程的信號名。
第二個可選的參數用於指定一些選項,預設選項為:
{ encoding: 'utf8',
timeout: 0,
maxBuffer: 200*1024,
killSignal: 'SIGTERM',
cwd: null,
env: null }
如果 timeout
大於 0,則當進程運行超過 timeout
毫秒後會被終止。子進程使用 killSignal
信號結束(預設為 'SIGTERM'
)。maxBuffer
指定了 stdout 或 stderr 所允許的最大數據量,如果超出這個值則子進程會被終止。