PythonでBASE64するときは注意しましょう。
Pythonで楽したつもりがハマった。
Pythonでテスト用のサーバを書いて動作確認してたんだけど、Python製のサーバをUbuntu上で動かしてる時は絶好調だったのに、Windows上で動かしたら動きません…というまあありがちな罠です。
実験
材料
とりあえずデータによって挙動が違うのかなと思ったので、バイナリデータとテキストデータを用意しましょう。バイナリデータはPythonのロゴ画像、テキストデータは何でもよかったんだけどロゴ画像をBASE64にしたものを使いましょう。
wget https://www.python.org/static/img/python-logo.png cat python-logo.png | base64 > python-logo.txt
スクリプト
対象のデータをファイルから読み込んでBASE64化するスクリプト。ポイントはファイルを読み込むときのモードの違い。
モード | 意味 |
rt | 読込専用でテキストモード |
rb | 読込専用でバイナリモード |
#! /usr/bin/env python # -*- coding:utf-8 -*- import os import sys import base64 def b64enc( target, mode ): return base64.b64encode(open(target,mode).read()) if __name__ == '__main__': if len(sys.argv) != 2: print 'Usage:python %s filename' % sys.argv[0] sys.exit(1) print 'reading file -> [%s] on [%s]' % (sys.argv[1], os.name) b1 = b64enc(sys.argv[1],'rt') b2 = b64enc(sys.argv[1],'rb') print 'b1 open("rt") b64encode data.len[%s]' % len(b1) print 'b2 open("rb") b64encode data.len[%s]' % len(b2) if b1 == b2 : print 'RESULT:b1 == b2' else: print 'RESULT b1 != b2'
動かしてみる
これをUbuntuとWindowsで動かしてみる
Ubuntu
$ ./b64.py python-logo.png reading file -> [python-logo.png] on [posix] b1 open("rt") b64encode data.len[13472] b2 open("rb") b64encode data.len[13472] RESULT:b1 == b2
$ ./b64.py python-logo.txt reading file -> [python-logo.txt] on [posix] b1 open("rt") b64encode data.len[18200] b2 open("rb") b64encode data.len[18200] RESULT:b1 == b2
どちらも問題ない。
Windows
$ ./b64.py python-logo.png reading file -> [python-logo.png] on [nt] b1 open("rt") b64encode data.len[8] b2 open("rb") b64encode data.len[13472] RESULT b1 != b2
$ ./b64.py python-logo.txt reading file -> [python-logo.txt] on [nt] b1 open("rt") b64encode data.len[18200] b2 open("rb") b64encode data.len[18200] RESULT:b1 == b2
バイナリデータをテキストモードで読み込むとダメ。
結論
バイナリデータはバイナリモードで開きなさい*1。
当たり前なんだけど、ちゃんとしないとダメってことで。
Pythonエンジニア養成読本[いまどきの開発ノウハウ満載!] (Software Design plus)
- 作者: 鈴木たかのり,清原弘貴,嶋田健志,池内孝啓,関根裕紀,若山史郎
- 出版社/メーカー: 技術評論社
- 発売日: 2015/04/17
- メディア: 大型本
- この商品を含むブログ (1件) を見る
*1:テキストデータは改行コードとかあるからテキストモードのほうがいいのかもしれないけどそこは双方で改行コードは統一するのが普通なのかなとか思うとバイナリモードでもいい気がする