標題:
"中文系統下打的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包的方法如下:
上面的命令是壓縮文件夾, 壓縮文件的方式類似.
其中cp這個參數指的是code page. 不同系統對於同一種編碼的code page可能會不同, 詳參Code page@wikipedia
如何知道一個編碼對應的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