使用するとき
fh = codecs.open(fname,'r','utf8')
fh.read()
ユニコードを返します。このユニコードを取得し、データベース ドライバー (mysql-python など) を使用してデータベースにデータを挿入する場合、ドライバーはユニコードをバイトに変換する必要があります。ドライバーは、によって設定されたエンコードを使用しています
con.set_character_set('utf8')
使用する場合
fh = open(fname, 'r')
次にfh.read()
、バイト文字列を返します。たまたま入っていたバイトに翻弄されfname
ます。幸いなことに、あなたの投稿によると、ファイルは UTF-8 でエンコードされています。データはすでにバイト文字列であるため、ドライバーはエンコードを実行せず、単にバイト文字列をそのままデータベースに通信します。
いずれにしても、UTF-8 でエンコードされたバイトの同じ文字列がデータベースに挿入されます。
codecs.openを定義するソース コードを見てみましょう。
def open(filename, mode='rb', encoding=None, errors='strict', buffering=1):
if encoding is not None:
if 'U' in mode:
# No automatic conversion of '\n' is done on reading and writing
mode = mode.strip().replace('U', '')
if mode[:1] not in set('rwa'):
mode = 'r' + mode
if 'b' not in mode:
# Force opening of the file in binary mode
mode = mode + 'b'
file = __builtin__.open(filename, mode, buffering)
if encoding is None:
return file
info = lookup(encoding)
srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
# Add attributes to simplify introspection
srw.encoding = encoding
return srw
encoding
特に、noが設定されている場合に何が起こるかに注意してください。
file = __builtin__.open(filename, mode, buffering)
if encoding is None:
return file
エンコーディングが設定されていない場合はcodecs.open
、基本的にビルトインと同じです。open
ビルトインは、メソッドがstropen
オブジェクトを返すファイル オブジェクトを返します。デコードは一切行いません。read
対照的に、エンコーディングを指定すると、に設定されcodecs.open
た が返されます。のメソッドを呼び出すと、通常、 Unicodeオブジェクトが返されます。最初に、指定されたエンコーディングを使用してstrオブジェクトをデコードする必要があります。StreamReaderWriter
srw.encoding
encoding
StreamReaderWriter
read
あなたの例では、str
オブジェクトは
In [19]: content
Out[19]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
エンコーディングを として指定すると、 はエンコーディング'ascii'
を使用しStreamReaderWriter
てデコードを試みます。content
'ascii'
In [20]: content.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
ascii
エンコーディングでは 0 ~ 127 の範囲のバイトしかデコードできず'\xe2'
、 の最初のバイトでcontent
ある にはその範囲外の序数値があるため、これは驚くべきことではありません。
具体的には:エンコーディングを指定しない場合:
In [13]: with codecs.open(filename, 'r') as f:
....: content = f.read()
In [14]: content
Out[14]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
content
ですstr
。
有効なエンコーディングを指定すると:
In [22]: with codecs.open(filename, 'r', encoding = 'utf-8') as f:
....: content = f.read()
In [23]: content
Out[23]: u'\u201cThank you.\u201d'
content
ですunicode
。
無効なエンコーディングを指定した場合:
In [25]: with codecs.open(filename, 'r', 'ascii') as f:
....: content = f.read()
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
を取得しUnicodeDecodeError
ます。