Windowsで文字化けを起こさずにzip圧縮するpythonスクリプト for Mac


## 背景
Mac -> Windows(日本語環境)でzipファイルを渡す時、Macデフォルトのzip圧縮ではファイル名の文字コードがutf-8のままになり、Windowsで解凍すると文字化けが起こります。
そうならないように [MacWinZip](http://tidajapan.com/macwinzipper) のようなソフトをインストールして圧縮するようにするということもできますが、インストールは何かと面倒臭いもの。
そこで、Python 2.7 で動作するWindows向けZip圧縮スクリプトを作成しました。

## Windows -> Mac の解凍
僕の使っている OSX Yosemite では Windowsで作成されたzipファイルを問題なく解凍できますが、linuxなどの環境ではsjisのファイル名が文字化けしてしまうことがあるらしいので、その場合、ファイル名をutf-8に変更して解凍するスクリプトを用いましょう([解凍スクリプトの例](http://matosus304.blog106.fc2.com/blog-entry-263.html))。

## 使い方

```shell-session
$ python win_zip.py <圧縮したいフォルダのパス>
```

## 注意

* 動作確認環境：Mac OSX Yosemite, Python2.7.6 (Python 2.4以降なら動作するはず)
* 動作は一通り確認しましたが、コード実行の責任は負いません。
* Macで作成される .DS_STOREなどの隠しファイルを一括で除外するため、 __隠しファイルは全てzipフォルダに含まれません__
* このコードで作成したzipファイルはWindowsでは文字化けなしに解凍できますが、逆にMacだと文字化けします。[上記の解凍スクリプト](http://matosus304.blog106.fc2.com/blog-entry-263.html)などを使いましょう。
* ファイルの内容は Utf-8のままです。sjisに変換するのはファイル名のみです。

__コード(win_zip.py)__

```python

# coding:utf-8
import os, sys, zipfile, shutil
from unicodedata import normalize

def mac_path_to_sjis(mac_path):
	# macのファイル名は濁点が分割されているため、その問題を解消
	# これを行わなければ、濁点がsjisに変更できない例外が発生する
	norm_path = normalize('NFC', unicode(mac_path,'utf8'))
	return norm_path.encode('sjis')

def check_yes_no(message):
	# raw_input returns the empty string for "enter"
	yes = set(['yes','y'])
	no = set(['no','n'])
	choice = raw_input(message + os.linesep).lower()
	if choice in yes:
		return True
	elif choice in no:
		return False
	else:
		print "Please respond with 'yes' or 'no'"
		return check_yes_no(message) # loop

def zip_dir(in_dir_path):
	in_parent_path, in_dirname = os.path.split(in_dir_path)
	os.chdir(in_parent_path)
	with zipfile.ZipFile(in_dirname + '.zip', 'w') as zip_file:
		for parent_path, dirs, files in os.walk(in_dirname):
			sjis_dir_path = mac_path_to_sjis(parent_path)
			os.makedirs(sjis_dir_path)
			for fname in files:
				if fname[0] == '.': continue # ignore all secret file
				file_path = os.sep.join((parent_path, fname)) # path of original file
				print 'zipping : {0}'.format(file_path)
				sjis_file_path = mac_path_to_sjis(file_path)
				if file_path == sjis_file_path:
					zip_file.write(file_path) # file name is all alphabet
				else:
					shutil.copyfile(file_path, sjis_file_path) # copy file in sjis file name
					zip_file.write(sjis_file_path)
					os.remove(sjis_file_path) # remove sjis format file
			# remove parent folder in sjis format
			os.removedirs(sjis_dir_path)


if __name__ == '__main__':
	if len(sys.argv) != 2:
		sys.exit('Only 1 argument(path of directory) has to be specified as argument!')
	zip_target_path = sys.argv[1]
	if os.path.exists(zip_target_path) == False:
		sys.exit('Directory {0} does not exists!'.format(zip_target_path))
	if zip_target_path.endswith(os.sep):
		zip_target_path = zip_target_path[0:-1] # remove seperator
	zip_path = zip_target_path + '.zip'
	if os.path.exists(zip_path):
		if check_yes_no('Zip file already exists. Do you want to replace? [y/n]') == False:
			print 'Bye'
			sys.exit()
	zip_dir(zip_target_path)
```

何か問題や改善点などございましたら、遠慮なくご教示ください。

*20150628: zipしたフォルダの階層が /Users/username/ から始まるようになっていたので、必要なフォルダだけzipするように修正。