OSに関連していて、言語に完全に依存していないため、ファイルをインプレースで編集することはできないことをここで読みました。何故ですか?C標準のfseek()は、インプレースファイル書き込みを定義していませんか?
5 に答える
Pythonでも検索できます。リンクした答えは、ファイルの途中に挿入ABC
できないことを示しているだけです( -> ABXC
)。
シークしてから書き込む場合、書き込まれるデータはすべて、ファイルのその位置(-> )の内容を上書きします。ABC
AXC
重要なのは、ファイルは(ディスク上にある)配列のようなものだということです。ディスク上の固定された場所を占めます。
配列の途中に何かを挿入する必要がある場合は、末尾の要素を移動する必要があります。そうしないと、これらが上書きされます。同じ概念がファイルにも当てはまります。ファイルの末尾部分を移動して、途中に何かを挿入する必要があります。
これに対する1つの例外は、ファイルの固定サイズのブロックを同じサイズの新しいブロックで上書きする必要がある場合です。次に、fseek()を使用して、上書きするだけで問題ありません。
問題はOSに関連しています。これは、OSがファイルシステムを使用してディスク上のデータをどのように編成するかに依存するためです。
通常、ディスクはファイルの内容を保存するために固定サイズのブロックに分割されます。バイトが上書きされると、そのバイトを含む(全体の)ブロックのみが再書き込みされます。ファイルが追加されると、おそらく最後のブロックが書き換えられ、追加されたデータのコンテンツを保存するために新しいブロックが割り当てられ、ファイルに「リンク」されます。これらの2つの操作は、このスキームでは効率的です。
ただし、一部のバイトが挿入または削除されると、通常、挿入/削除の変更を含む最初のブロックからファイルを書き換える必要があります。
ファイルの書き換えにかかる時間を短縮することは技術的に可能です。挿入の場合、OSは挿入されたデータに新しいブロックを割り当て、それをファイルに「リンク」して、1つまたは2つの隣接ブロックを書き換えることができます。削除の場合、OSはブロック内の有効なバイト数を減らしたり、ブロックを書き換えたり、ファイル内のブロックを「再リンク」したりできます。免責事項として、私が今述べた「解決策」は、特定のファイルシステムがどのように構成されているかに依存します。ただし、ファイルの書き換えコストを削減すると、通常、後で読み取り操作がヒットするか、内部の断片化が発生します。
ある日、読み取り操作のパフォーマンスを維持しながら、ディスク上のデータを効率的に挿入/削除できるデータ構造を誰かが発明すれば、問題は解決するかもしれません。
その場でファイルを変更できます。置換するデータが置換するデータと同じサイズの場合(より小さく、パディングするだけです)。それが大きい場合はどうなりますか?さて、それでは、変更後のすべてをとにかくディスクに書き直す必要がありますよね?また、すべての場合に最後に十分なスペースがあるとは限りません。そのため、ファイルを完全に新しい場所に移動する必要がある場合があります。
明らかに、これにより有効なユースケースはかなりまれになります。あなたがそうする本当に正当な理由がない限り、通常それは価値がありません。Pythonでインプレース変更APIにアクセスできるかどうかについては...わかりません。
もちろん、ファイルをその場で編集することもできます。
import struct
RECSIZE = struct.calcsize('<i')
fp = open('name.txt', 'r+b')
fp.seek(132 * RECSIZE) # go to record number 132
fp.write(struct.pack('<i', 42))
fp.seek(132 * RECSIZE)
assert struct.unpack('<i', fp.read(RECSIZE)) == 42
これは、そうする最も一般的な理由と制限も示しています。