Pythonの勉強 : テキストバッファを扱うStringIO

ファイルオブジェクトみたいなインターフェースでテキストバッファを扱うStringIOというモジュールをさわってみます。


基本的な使い方は以下のような感じで、バッファに文字列を書き込んだり、読み出したりできます

from StringIO import StringIO

# バッファへ書き込む
output = StringIO()
output.write(u'あ…ありのまま 今 起こった事を話すぜ!\n')
output.write(u'『おれは奴の前で階段を登っていたと思ったらいつのまにか降りていた』\n')

# 書き込まれた値を取り出す
print output.getvalue()
# => あ…ありのまま 今 起こった事を話すぜ!
# => 『おれは奴の前で階段を登っていたと思ったらいつのまにか降りていた』

# バッファのクローズ
output.close()


# コンストラクタに文字列を渡せる
input = StringIO(u'あ…ありのまま 今 起こった事を話すぜ!\n')

# posは0
print input.pos
# => 0

# バッファから読み込む
print input.read()
# => あ…ありのまま 今 起こった事を話すぜ!

# posは21になる
print input.pos
# => 21

# バッファに追記
input.write(u'『おれは奴の前で階段を登っていたと思ったらいつのまにか降りていた』\n')

print input.getvalue()
# => あ…ありのまま 今 起こった事を話すぜ!
# => 『おれは奴の前で階段を登っていたと思ったらいつのまにか降りていた』


# seekとかreadlinesも使えます
input.seek(0)
for line in input.readlines():
    print line
    # => あ…ありのまま 今 起こった事を話すぜ!
    # => 『おれは奴の前で階段を登っていたと思ったらいつのまにか降りていた』


StringIOと同じインターフェースで高速化されているcStringIOというのもあります。


cStringIOはちょっと注意が必要で、StringIOと全く同じ動きをするわけではありません

例えば、上記の例をそのままcStringIOで動かしたらエラーになります。

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-6: ordinal not in range(128)

cStringIOはStringIOと違って、Unicodeを受け付けることができないんですね


また、コンストラクタに文字列を渡した場合、「追記」をすることはできません。

from cStringIO import StringIO

# コンストラクタに文字列を渡せる
input = StringIO('あ…ありのまま 今 起こった事を話すぜ!\n')

# バッファに追記
input.write('『おれは奴の前で階段を登っていたと思ったらいつのまにか降りていた』\n')
# => AttributeError: 'cStringIO.StringI' object has no attribute 'write'

StringIOとcStringIOは微妙に仕様が違うので、以下のようにimportしてどちらでも動かせるように意図している場合は、

1. Unicodeを渡さない
2. コンストラクタに文字列を渡して作成したバッファには書き込みをしない

などの注意が必要ですね

try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO

参考)
http://www.python.jp/doc/2.7/library/stringio.html#module-cStringIO