これは、プログラミング言語に依存しない問題として発生します。
内容のファイルがあります
aaabddd
私がC
後ろに挿入したいときはb
、私のコードを書き直す必要ddd
があります
aaabCddd
C
この位置に挿入できないのはなぜですか?
Java、Pythonなどではできません。Linux、Windowsなどではできません。私は正しいですか?
C
追加の書き込みなしに単純に挿入できない理由がわかりません。なぜこれがそうであるのか誰かが説明してくれませんか?
これは、プログラミング言語に依存しない問題として発生します。
内容のファイルがあります
aaabddd
私がC
後ろに挿入したいときはb
、私のコードを書き直す必要ddd
があります
aaabCddd
C
この位置に挿入できないのはなぜですか?
Java、Pythonなどではできません。Linux、Windowsなどではできません。私は正しいですか?
C
追加の書き込みなしに単純に挿入できない理由がわかりません。なぜこれがそうであるのか誰かが説明してくれませんか?
回答:
ほとんどのファイルシステムは、物理ディスク上で必ずしも連続しているわけではないが、ポインター構造を介してリンクされている個々のブロックにファイルの内容を格納するため、このようなモード(「追加」または「上書き」ではなく「挿入」)が必要と思われます。コンテンツ全体を読み取り、バイトストリームを編集して、コンテンツ全体を再書き込みします。
ただし、良くも悪くも、ファイルシステムのUNIXセマンティクスは1970年代の「ラフでシンプルな」パラダイムに沿って設計されました。すべてのことを実行できますが、必ずしも最も効率的な方法ではありません。現在、仮想ファイルシステムレイヤーに新しいファイルオープンモードを導入し、主要なファイルシステムがそれをサポートすることを期待することはほとんど考えられません。これは私のうんざりですが、残念ながらすぐに解決される可能性は低いです。
理論的には、このようなことを可能にするファイルを実装できます。ただし、最大の柔軟性を得るには、ファイル内のすべてのバイトと共に次のバイトへのポインタを格納する必要があります。64ビットのポインターを想定すると、ファイルの9バイトごとに8つが内部ポインターで構成されることになります。したがって、1000バイトの実際のデータを格納するには、9000バイトのスペースが必要になります。また、ディスクから大きな連続したデータブロックを読み取るのではなく、各バイトを読み取り、ポインターを読み取り、ポインターに従って次のバイトを読み取る必要があるため、ファイルの読み取りも遅くなります。
明らかに、この種のアプローチは実用的ではありません。ただし、ファイルを32 kbブロックなどに分割することもできます。これにより、ファイル内の32 kbの境界に32 kbのデータを追加するのが比較的簡単になります。ファイルの5番目のバイトとして1バイトを追加するのは簡単ではありません。ただし、すべてのブロックにいくらかの空き領域を予約すると、その単一ブロック内のデータにのみ影響するデータの小さな追加が行われる可能性があります。もちろん、ファイルサイズの点でペナルティはありますが、合理的なペナルティになる可能性があります。ただし、予約する領域とブロックを分割する方法を理解することは、特定のアプリケーションでは汎用システムよりもはるかに簡単になる傾向があります。あるコンテキストで機能するものは、ファイルアクセスや修正特性。
実際、ファイルとのやり取りに多くの時間を費やす多くのシステムは、特定のファイル抽象化を実装するときに、上で説明したようなものを実装しています。たとえば、データベースは一般的に、「ブロック」の概念をI / Oの最小単位として実装し、通常、将来の拡張に備えてある程度のスペースを確保するので、テーブルの行を更新すると、ファイル全体を再書き込みするのではなく、そのデータが格納される1つのブロック。もちろん、データベースが異なれば、実装も異なり、トレードオフも異なります。
「問題」は、ファイルがバイト単位でストレージメディアに書き出される方法に要約されます。
最も基本的な表現では、ファイルはディスク(別名ストレージメディア)に書き込まれた一連のバイトにすぎません。したがって、元の文字列は次のようになります。
Address Value
0x00 `a`
0x01 `a`
0x02 `a`
0x03 `b`
0x04 `d`
0x05 `d`
0x06 `d`
そしてC
、位置0x04 に挿入したいとします。これには、新しい値を挿入できるように、バイト4〜6を1バイト下にシフトする必要があります。そうしないと、現在0x04にある値が上書きされてしまい、必要な値が上書きされます。
Address Value
0x00 `a`
0x01 `a`
0x02 `a`
0x03 `b`
0x04 `C`
0x05 `d`
0x06 `d`
0x07 `d`
したがって、新しい値を挿入した後にファイルの末尾を再書き込みする必要があるのは、挿入された値を受け入れるためのスペースがファイル内にないためです。そうしないと、そこにあったものを上書きします。
補遺1:の値をで置き換えたい場合は、文字列の末尾を書き換える必要はありません。値を同じサイズの値で置き換える場合、書き換えは必要ありません。b
C
補遺2:あなたは、文字列交換したい場合ab
とC
、あなたが考えに必要なファイルのギャップを作成してきたように、ファイルの残りの部分を再書き込み。
補遺3:ブロックレベルの構成が作成され、大きなファイルの処理が容易になりました。1M分のファイルの連続したスペースを見つける必要はなく、代わりに1M分のブロックを見つけて書き込むだけで済みます。
理論的には、ブロックが提供するのと同様のバイト単位のリンクを行うファイルシステムを構築できます。次に、|を更新して新しいバイトを挿入できます。適切なポイントのポインタから。私はそれでのパフォーマンスがかなり悪いだろうという推測を危険にさらすでしょう。
グランドマスターBが示唆され、視覚的にファイルがどのように表現されるかを理解するために積み重ねられたドミノの画像を使用しています。
すべてを転倒させることなく、ドミノの行内に別のドミノを挿入することはできません。他の人を線の下に移動して、新しいドミノ用のスペースを作成する必要があります。行の下にドミノを移動することは、挿入ポイントの後にファイルの末尾を書き換えることと同じです。
ファイルへの挿入は、潜在的に長期的な「高価な」影響と追加の障害モードを伴う「高価な」(時間を浪費し、スペースを消費する)操作と見なされるため、ほとんどのファイルシステムでは実装されていません。
挿入のセマンティクスを持つファイルシステムは、おそらくshift&insert(大きなファイルの前に挿入すると非常に高価になる可能性がありますが、長期的な副作用はほとんどありません)、または可変長の割り当てサイズを持つ一般的なヒープの割り当て(場合によっては、非常に不適切なパフォーマンス([Stop-the-world GC]の最中にファイルを保存しようとするインタラクティブユーザーの顔を想像してください!))。
実験したい場合は、挿入を実装するJavaまたはPythonでファイルI / O抽象化を簡単に構築できます。あなたが成功し、それが行儀の良いパフォーマンス特性を持っている場合、あなたは優れた研究論文の基礎を持っています。幸運を。
ファイルの途中にバイトのブロックを挿入する最も効率的な方法は、次のとおりです。
最初に、挿入ポイントの後のすべてを読み取り、次に挿入するスペース分だけ書き戻す必要があります。次に、「挿入」データを正しい場所に書き込むことができます。パフォーマンスが非常に低いため、ネイティブでサポートされていません。
ファイルに直接アクセスする場合、より高度な構造を構築するために使用できる低レベルを使用しています。挿入など、必要な種類のアクセスを可能にするデータを使用してデータベースを構築することを検討してください。
ファイルを反復処理するだけで、指定したオフセットへのランダムアクセスを実行しない場合は、コストが低くなります。ファイル内のオフセットによるランダムアクセスが必要な場合は、挿入ポイント以降のすべてのバイトのインデックスを更新する必要があります。
一般に、インデックスのデータ構造、インデックスを格納するためのメモリ、およびインデックスを更新するための追加のディスクアクセスに料金がかかります。