Python での単純なアプローチを使用したファイルのコピーは、通常、次のようになります。
def copyfileobj(fsrc, fdst, length=16*1024):
"""copy data from file-like object fsrc to file-like object fdst"""
while 1:
buf = fsrc.read(length)
if not buf:
break
fdst.write(buf)
(ちなみに、このコード スニペットは shutil.py からのものです)。
残念ながら、これには私の特別なユースケース (スレッド化と非常に大きなバッファを含む) では欠点があります [イタリック体の部分は後で追加]。まず、read() の呼び出しごとに新しいメモリ チャンクが割り当てられ、次の反復で buf が上書きされると、このメモリが解放され、同じ目的のために新しいメモリが再度割り当てられることを意味します。これにより、プロセス全体が遅くなり、ホストに不要な負荷がかかる可能性があります。
これを回避するために、私は file.readinto() メソッドを使用していますが、残念ながら、非推奨であり、「使用しない」と文書化されています。
def copyfileobj(fsrc, fdst, length=16*1024):
"""copy data from file-like object fsrc to file-like object fdst"""
buffer = array.array('c')
buffer.fromstring('-' * length)
while True:
count = fsrc.readinto(buffer)
if count == 0:
break
if count != len(buffer):
fdst.write(buffer.toString()[:count])
else:
buf.tofile(fdst)
私の解決策は機能しますが、欠点も 2 つあります。まず、readinto() を使用しないでください。なくなるかもしれません(ドキュメントによると)。第二に、 readinto() を使用すると、バッファに読み込むバイト数を決定できず、 buffer.tofile() を使用して書き込みたいバイト数を決定できないため、最後のブロックの面倒な特殊なケース (これも不必要に高い)。
私はarray.array.fromfile()を見てきましたが、「そこにあるすべて」を読み取るために使用することはできません(読み取り、次にEOFErrorをスローし、処理されたアイテムの数を配布しません)。また、エンディングの特殊ケースの問題に対する解決策ではありません。
私がやりたいことをする適切な方法はありますか?たぶん、私が望むことをする単純なバッファクラスまたは類似のものを見落としているだけです。