標籤:ruby zip 壓縮解壓
在UNIX下的我們怎麼會淪落到用ruby寫壓縮和解壓工具呢?直接上shell啊!但是請允許本貓這次可恥的用ruby來玩玩吧!其實ruby GEM中有很多壓縮解壓包,我選的是Zip,也許是因為名字元合KISS原則吧!不過在編寫中發現Zip中的某些類沒有文檔中所說明的執行個體方法,也許在某個平台上還未實現??
話先說到前頭,這個工具如果解壓有重名檔案的情況會直接覆蓋原檔案而不會有任何提示!測試時務必注意,如果造成一些檔案丟失可別怪本貓啊!
代碼也考慮到多檔案的情況,如果是壓縮多檔案則預設會單獨壓縮每一個檔案,比如:zip.rb a b c d 會產生a.zip .. d.zip四個壓縮檔;但是我也考慮到現實中的情況,單獨寫了一個zip_n2one方法將多個檔案壓縮到一個檔案中去,這個可以看代碼實現,很清楚;如果是解壓多檔案則會依次解壓縮每個檔案,如果檔案有重名會像之前說的直接覆蓋。
代碼未考慮到如果多個壓縮檔的basename相同的情況,即zip.rb a.dat ../a.dat ~/a.dat的情況。如果真是如此,我估計壓縮包中最終只有一個entry檔案就是最後一個~/a.dat,要避免這種情況需要做額外的判斷,我這裡不是寫真正的生產工具,只是個玩具嘛,所以點到為止了。
在測試代碼中發現一個問題:就是如何?刪除一個目錄下的所有檔案,但除了zip檔案。這個直接用shell吧:
[email protected]: tmp$ls|grep -v .*.zip|xargs -n1 rm
如果是刪除所有zip檔案呢?可以這樣:
[email protected]kissAir: tmp$ls|grep .*.zip|xargs -n1 rm
不過傻了吧,為什麼不直接 rm *.zip呢? 下面上代碼,寫的比較快,所以有些實現略顯“笨拙”,該最佳化的沒最佳化,該重構的沒重構!最後再提醒下:如果要多個檔案打包在一個zip中請使用zip_n2one方法,注意zip_n2one方法的最終zip檔案名稱是硬式編碼,這也讓人稍感不快,但這終歸只是測試,所以各位童鞋可以隨時重寫哦:
#!/usr/bin/ruby#簡單的壓縮解壓工具#code by 侯佩|hopy 2014-12-01require 'zip/zip'def sh_e(e)e.backtrace.each {|s|puts s}puts "ERR : #{e.to_s} \n"end#取得zip檔案中所有的entry名稱def get_entries_name(path)full_path = File.expand_path(path)entries = []Zip::ZipInputStream::open(full_path) do |io|while (entry = io.get_next_entry)entries << entry.nameendendentriesenddef unzip(path)full_path = File.expand_path(path)entries = get_entries_name(path)Zip::ZipFile.open(full_path) do |f|entries.each do |entry|f.extract(entry,entry) {true}puts "unzip #{entry} succeed!"endendrescue =>esh_e(e)exit 3enddef zip_n2one(paths,zip_path)full_zip_path = File.expand_path(zip_path)f = Zip::ZipFile.open(full_zip_path,Zip::ZipFile::CREATE)paths.each do |path|full_path = File.expand_path(path)f.add(File.basename(path),full_path) {true}puts "add #{path} to #{full_zip_path}"endf.closeputs "all files is zip to #{full_zip_path}"rescue =>esh_e(e)exit 4enddef zip(path)full_path = File.expand_path(path)dir_name = File.dirname(full_path)only_name = File.basename(path,".*")only_zip_name = only_name + ".zip"full_zip_path = dir_name + '/' + only_zip_namef = Zip::ZipFile.open(full_zip_path,Zip::ZipFile::CREATE)f.add(File.basename(path),full_path) {true}f.closeputs "create #{full_zip_path} succeed!"rescue =>esh_e(e)exit 5endis_unzip = falsecase ARGV.countwhen 0puts "usage #{$0} [-u] files [...]"exit 1when 1if ARGV[0] == "-u"puts "ERR : unzip without filename!"exit 2endelseif ARGV[0] == "-u"is_unzip = true#將選項-u從參數列表中移除ARGV.shiftendendif is_unzipARGV.each {|file_path|unzip(file_path)}else#ARGV.each {|file_path|zip(file_path)}zip_n2one(ARGV,"total.zip")end
ruby利用Zip Gem寫一個簡單的壓縮和解壓的小工具