标題:
"中文系統下打的zip壓縮包, 日文系統下檢視時檔案名亂碼問題"解決方案:
- 在壓縮/解壓縮zip包時, 指定檔案名的編碼方式
正文開始......
我們公司使用的作業系統是中文, 我們經常需要把一些檔案壓成zip包, 然後發給日本總公司,
當然, 日本同僚使用的是日文作業系統.
這個時候, 如果zip包中所有檔案都是ascii字元, 那麼沒問題,
否則, 如果zip包中包含漢語或者日語字元那麼對方看到便會出現亂碼.
原因在于:
無論是windows預設的zip壓縮工具, 還是7-zip, 在zip壓縮或者解壓縮的時候,使用的都是系統預設編碼來表示檔案名,
也就是說windows上面是gb2312, 而日文windows上面用的是shift-jis
使用gb2312編碼的zip檔案名, 在日文windows上面使用shift-jis來檢視, 自然是亂碼的.
還有一類人, 應該也受這個問題所苦.
他們(也包括我)有時候會從日本的站點(share等)下載下傳一些壓縮包(漫畫之類),
這些壓縮包是在日文系統下壓縮的, 如果檔案名包含日語, 在我們中文的系統上解壓就會出現亂碼.
我以前的解決辦法是弄一個日文的虛拟機,
無論是解壓還是壓縮都在虛拟機上進行.
(前一個公司, 日本和中國都使用日文的windows, 便沒有這個問題)
然而為了一個壓縮包就開要打開一個虛拟機,難免有些麻煩
是以我的期望是:
在壓縮zip包,或者解壓縮zip包時, 能夠制定對檔案名的編碼方案.
比如我在中文系統上制作一個壓縮包, 我可以指定: 對檔案名使用日文編碼進行編碼.
這樣以來, 在日文os上檢視時,變不會産生亂碼.
調查了一下, 這個問題可以通過DotNetZip 來解決,
DotNetZip對自己的介紹是: Zip and Unzip in C#, VB, any .NET language
給我們提供的資源也很貼心:
有源代碼, dll, 還有基于這些源代碼和dll的工具, 有指令行的, 也有GUI的zip工具,
這些工具也有源代碼, 同時還提供了C#,VB等語言的例子(我看了一下, 內建到自己的程式中也很友善).
download 頁面在這裡.
我下載下傳的是: DotNetZipLib-DevKit-v1.9.zip
解壓縮之後在DotNetZipLib-DevKit-v1.9\Tools\路徑下面,會有兩個指令行工具: Zipit.exe 和 UnZip.exe
(其實還包括一個GUI工具,叫DotNetZip-WinFormsTool.exe, 不喜歡指令行的移步這裡)
zipit.exe是壓縮的指令行, UnZip.exe是解壓縮, 他的參數類似, 都支援指定編碼.
這次我使用的工具就是他們. 他們的指令行參數在這裡 .
也可以從這個連結導航進來: DotNetZip - Zip file manipulation in .NET languages
使用這個指令行工具, 指定編碼打zip包的方法如下:
Zipit.exe "C:\_TryZipIt\測試檔案夾.zip" -r+ -cp 932 "C:\_TryZipIt\測試檔案夾"
上面的指令是壓縮檔案夾, 壓縮檔案的方式類似.
其中cp這個參數指的是code page. 不同系統對于同一種編碼的code page可能會不同, 詳參Code [email protected]
如何知道一個編碼對應的code page呢?
可以通過如下代碼取得(C#為例), 或者google吧.
根據結果, 日文windows的預設編碼shift-jis對應的code page是932.
var cp_shiftjis = System.Text.Encoding.GetEncoding("shift-jis").CodePage;
var cp_eucjp = System.Text.Encoding.GetEncoding("euc-jp").CodePage;
var cp_gbk = System.Text.Encoding.GetEncoding("GBK").CodePage;
var cp_gb2312 = System.Text.Encoding.GetEncoding("gb2312").CodePage;
然而使用上面的指令行, 每次輸入的參數還是太多,于是我寫了一個ruby腳本包裝了一下上面的指令行.
這個腳本每次隻接受一個參數, 他代表一個檔案或者檔案夾.
他的功能是, 在跟輸入參數相同的檔案夾下, 建立一個同名的.zip檔案.
相當于7-zip郵件菜單中的: 添加到 "XXX.zip"
使用這個腳本的前提是你要将zipit.exe放到path中
# encoding : utf-8
def show_usage_and_exit(msg)
puts "please input the path to zip"
puts "error msg: #{msg}"
exit 0
end
show_usage_and_exit("no path to zip") unless ARGV.length == 1
#puts ARGV[0].dup.force_encoding("GBK").encode('utf-8')
zip_input = ARGV[0].dup.encode('utf-8')
show_usage_and_exit("path does not exist") unless File.exist? zip_input
if File.directory? zip_input
zip_output = zip_input + ".zip"
else
zip_output = zip_input.gsub(/\.\w{2,4}\z/,".zip")
end
File.delete zip_output if File.exist? zip_output
zip_cmd = "#{%Q<Zipit.exe "#{zip_output.encode("GBK")}" -r+ -cp 932 "#{zip_input.encode("GBK")}">}"
puts "the path to zip is:\n\t" + zip_input;
puts "the target path is:\n\t" + zip_output;
puts "the zip command is:\n\t" + zip_cmd.encode("utf-8");
puts "\n------------------------------ zip process start...---------------------\n\n"
#puts `#{zip_cmd}`
puts `#{zip_cmd}`.encode("utf-8")
在windows上面, 除了7-zip, 和DotNetZip以外,
還可以使用一些其他的指令和腳本, 來制作zip包.
參下面這些連結:
Can you zip a file from the command prompt using ONLY Windows' built-in capability to zip files?
Does Windows have a built-in ZIP command for the command line?
Can Windows' built-in ZIP compression be scripted?
Zip and UnZip Files Using the Windows Shell (XP, Vista, 2003 and 2008) and VBScript
-----------------------------------------------------------------------------------------------------------------------------
追記:2012.07.02
-----------------------------------------------------------------------------------------------------------------------------
重新新封裝了一下這個ruby腳本,
在一個腳本中同時支援zip和unzip.
如果輸入參數不是以.zip擴充名結尾, 那麼使用日文系統的編碼, 将其在目前檔案夾中壓縮.
如果輸入參數是以.zip擴充名結尾, 那麼使用日文系統的編碼, 将其在目前檔案夾中解壓.
其中用到zipit和unzipit兩個指令
zipit是把DotNetZipLib的指令行工具直接拷貝path中,
unzipit是把DotNetZipLib的叫做unzip.exe的指令改名而來.
# encoding : utf-8
def show_usage_and_exit(msg)
puts "please input the path to zip"
puts "error msg: #{msg}"
exit 0
end
def check_parameter
show_usage_and_exit("no path to zip") unless ARGV.length == 1
show_usage_and_exit("path does not exist") unless File.exist? ARGV[0].dup.encode('utf-8')
puts "===your input is===:\n" + ARGV[0].dup.encode('utf-8')
end
def run_cmd(cmd)
puts "===the command is===:\n" + cmd.encode("utf-8") + "\n\n---------- command start...------------\n"
puts `#{cmd}`.encode("utf-8") #puts `#{cmd}`
end
def to_zip_cmd(input_str)
if File.directory? input_str
zip_output = input_str + ".zip"
else
zip_output = input_str.gsub(/\.\w{2,4}\z/,".zip")
end
File.delete zip_output if File.exist? zip_output
"#{%Q<Zipit.exe "#{zip_output.encode("GBK")}" -r+ -cp 932 "#{input_str.encode("GBK")}">}"
end
def to_unzip_cmd(input_str)
"#{%Q<Unzipit.exe -cp 932 -d "#{File.dirname(input_str).encode("GBK")}" "#{input_str.encode("GBK")}">}"
end
check_parameter
input_str = ARGV[0].dup.encode('utf-8') # ;puts ARGV[0].dup.force_encoding("GBK").encode('utf-8')
if input_str.end_with? '.zip'
run_cmd(to_unzip_cmd input_str)
else
run_cmd(to_zip_cmd input_str)
end