生のバイトをファイルに書き込むことに危険はありますか?[閉まっている]


12

私は、プログラミングパールの問題、具体的には、最大で10,000,000個の整数を含むファイルをソートするプログラムの実装(列1、問題3)に取り組んでいます。本はデータをファイルに保存する方法を指定していないので、整数を未加工バイトとして保存することを検討しています(未加工バイトを適切なオプションにする他の制約があります)。これほど低いレベルで働いたことはないので、注意すべき危険があるかどうか知りたいです。たとえば、生のバイトをファイルに書き込むときに、何らかの種類のファイルの終わりのシーケンスを誤って使用することを心配する必要がありますか?

編集:

私は今、私の質問がどれほど広いかを理解しています。ディスク上の他のファイルを誤って上書きするなど、より壊滅的な種類の問題を意味していました。申し訳ありませんが、私は元々明確ではありませんでした。


6
Programming Pearlsは非常に古い本です。最新のデスクトップマシンの10 ^ 7整数全体をメモリに簡単に読み込み、並べ替えてから再度書き込むことができます。その章の元のポイントを取得するには、いつでも読む数を全体の数分の1に制限します。または、ファイルサイズを約10 ^ 10整数に増やします。
カレブ14

3
実際、「危険」という言葉を聞いたとき、PCが爆発したり、銀行口座が削除されたりするようなことを考えています。そして、あなたのプログラムがエアバスや発電所の制御に使用されていない限り、あなたが考えていることを試しても実際に「危険」なことは起こらないと仮定するのがおそらく最も安全だと思います。
Doc Brown 14


2
@delnan数年前、EOFキャラクターの神話が流行したとき、当時の多くのコピープログラムが行っていた「EOFキャラクターまでのコピー」に基づいたコピー保護システムを思い出します。一部のプログラムは、関連するテキストファイルのEOFマーカーの後で、割り当てられたファイルの終わりの前にチェックする追加データを配置します。コピープログラムは、クリーンインストールを検証する余分なデータをコピーしません...ああ...ノスタルジア。

危険?「これを行うと、コンピューターが爆発しますか?」いや。
jwenting

回答:


11

遭遇する唯一の危険は、小さなエンディアンと大きなエンディアンネス(最上位または最下位バイトが最初に書き込まれるかどうか)です。ただし、同じ環境にいる場合は問題ありません。往復の書き込み/解析の一般的な保証に加えて。

ファイルシステムは、あらゆるバイトシーケンスを処理するように設計されています。


2
最後の行に+1。大小の問題が唯一の問題かどうかはわかりません。たとえば、OPは整数間の境界がどこにあるかについて混乱する可能性があります。とにかく良い答え。
カレブ14

27

いいえ、実際、これはいくつのファイル形式が機能するかです。このようなバイナリファイルの一般的な例には、画像や音楽/オーディオファイルが含まれます。

ファイルとそこから読み取ったデータの整合性を維持するには、次のガイドラインに従ってください。

  • 常に同じモード(テキストまたはバイナリ)を使用してファイルを開いてください(読み取りまたは書き込み)。主な違いは、テキストモードでは改行が重要であり、ファイルの読み取り時に改行文字が "使用されない"ことです(使用されている特定のライブラリによって異なります)。テキストモードでは、Unicode変換も実行される可能性があり、これは非Unicodeデータで停止する可能性があります。
  • 文字列以外のデータを読み取るときは、書き込みと同じデータ型を使用して必ず読み取ってください。たとえば、ファイルの最初の4バイトが説明的な整数である場合、整数を取得/提供するメソッドを使用して読み取りおよび書き込みを行い、整数が一貫して処理されるようにしてください。異なるマシンでは同じデータ型のサイズが異なる場合があり、同じマシンでデータ型を混在させるとデータの意味が変わる可能性があります(たとえば、長い整数の途中のビットを符号ビットとして解釈する)。
  • エンディアンネス:使用しているライブラリがこれを一貫して処理しない場合、自分で処理する必要がある場合があります。たとえば、Javaは常にマルチバイトタイプに対してネットワークバイト順(ビッグエンディアン)を使用します。CおよびC ++は、ライブラリの実装者が決定したもの(通常はプロセッサと同じもの)を使用します(Intelではリトルエンディアン、他のほとんどではビッグエンディアン)。これが1つのシステムでの迅速な演習である場合、それほど重要ではありませんが、これに注意を払い、必要に応じてその周辺のコードを作成することは依然として良い習慣です。

具体的な詳細は、フレームワーク、プラットフォーム、および言語によって異なりますが、これはファイルI / Oの基本的な「落とし穴」をカバーするはずです。


3
非文字列データの追加ポイント:各タイプに一貫したバイト数を使用するようにしてください。CおよびC ++では、an intは2〜8バイトまたはそれ以上の任意の場所に配置できます(実際にはオクテット)。
バートヴァンインゲンシェナウ14

これは、2番目のポイント、たとえば32 v。64ビット整数に暗黙的に含まれています。それらは異なるデータ型になります。

明示的にすることもできます。int2つの異なるマシンで異なるデータ型と見なされる可能性があることは明らかではありません。
バートヴァンインゲンシェナウ14

9

既に述べたすべての落とし穴に加えて、既存の形式でデータを読み書きするのではなく、新しいバイナリファイル形式を作成する場合は、ファイルヘッダーを含めることが絶対に重要です:最初にデータのブロックファイル形式を明確に識別し、必要なメタデータを記録するファイルの。

適切なファイルヘッダーには、少なくとも3つのことが含まれます。

  • 少なくとも4バイトの「マジックナンバー」。マジックナンバーMUSTは、RFC2119、非常に最初のNでなければなりませんが、あなたが掘ることができ、印刷可能なASCII文字ではない、少なくとも1つのバイトを含まなければならない他のファイル形式で使用されていない決して、ファイルのバイト。本当に徹底的なマジックナンバーの設計方法については、PNG仕様を参照してください。既存のマジックナンバーのデータベースについては、コマンドのソースコードをご覧ください。file(1)

    マジックナンバーのポイントは、インバンドでファイルの形式を明確にラベル付けすることです。マジックナンバーを含めない場合、またはマジックナンバーをファイル内の最初のものではない場合、プログラムがファイルを他の種類のファイルと誤認するリスクがあり、データ損失、ウイルスエスケープ検出などにつながります。大災害。

  • ファイル形式のバージョンの表示。あなたが大幅にあなたのファイル形式を修正しているつもりはありませんていると思う場合でも、マジックナンバーがあることの後に、次の2つのバイトを作成00 00し、これはいくつかの明確なエンディアン(どちらかあなたのような、16ビットのバージョン番号であるが、その文書選びます1つとファイル全体に貼り付けます)、後続のデータの意味が根本的に変更されると増分されます。あなたの将来の自己はあなたに感謝します。

    (PNG仕様はここで異なるルートを取り、チャンク形式が凍結され、形式への今後のすべての変更が新しいチャンクタイプの形式になることを指定しています。これも有効ですが、バイナリデータ処理の初心者。PNGを設計した人々は、画像フォーマットでの長年の経験に基づいていました。)

  • ファイルに任意のメタデータを埋め込むための何らかのメカニズム。これは、次の 2バイトをヘッダーの最後から実際のデータの先頭までの16ビットオフセットにするという単純なもので、RFC 822のようなUTF-8キーと値のペアとして解釈される(つまり、「Tag: value\n」—このルートを使用する場合は、長い行の折り畳みを許可しないことをお勧めします)。繰り返しますが、PNGはかなり賢いです。


独自のファイル形式を作成する必要はありません...データを画像として保存するだけです。サポートされるように、次元を変更する必要がある場合があります(10k x 1kなど)。または、FITSを使用できます。データが単一の配列よりも複雑な場合は、HDFCDFまたはNetCDFを使用できます。
ジョー14

シンプルにすることをお勧めします。256の異なるバージョンで十分です。そうでない場合は、バージョン255のサブバージョンとして追加のバージョンを考案できます。同様に、メタデータの場合は、実際に必要なときにバージョンに追加するだけで十分です。@Joe Image ??? 事前に全員を混乱させることで、潜在的なフォーマットの混乱を回避しています!
maaartinus

@maaartinusバージョンフィールドを2バイトにすると、フォーマットデザイナはエンディアンネスを前もってコミットします。メタデータ用のスペースは常にバイナリ形式のバージョン0である必要があります。そうしないと、ID3のようなひどい処理が必要になります。フォーマットのバージョンバンプではなく、新しいチャンクタイプを介した拡張性に関するPNG仕様のロジックには、多くの同情があります。ただし、チャンク構造のファイルは独自の複雑さをもたらすため、単純な場合にはお勧めしません。これらの問題の多くを既に処理している汎用形式としてHDFを推奨したいと思いまし
zwol

2

異なるアーキテクチャでは、整数の表現が異なります。ここでの主なリスクは、マシンAの整数のバイト表現を保存し、それを読み戻してマシンBの内容を整数として解釈しようとすることです。マシンAとBの整数サイズおよび/またはエンディアンネスが異なる場合、ほとんどの場合、未定義の動作(Cなど)または例外が発生します。

これは単なるプログラミング例であり、「実際の」プログラムではないため、実際には問題ではありません。これが実際のプログラムである場合、独自のアプリケーション固有のバイナリ形式を展開することは通常、良い考えではありません。SQLiteやJSON、YAML、XMLなどの文字列ベースのシリアル化形式など、より優れたソリューションがあります。単一の値の場合、文字列に変換するだけで十分です。単純なリストの場合、1行に1つの文字列を保存し、それを読み戻すときに改行で入力を単純に分割できます。


一般的には同意しますが、JSONまたはXMLは10 ^ 7個の数字を含むファイルのサイズを大幅に増加させます。また、通常は一度に読み取られて解析されますが、問題の章では、使用可能なメモリに収まらないほど多くのデータを含むファイルのソートについて説明します。
カレブ14

それはあなたが何をしているかに依存します。SQLのパフォーマンスヒットとロールユアオウンのパフォーマンスヒットが大きい場合があります。私が最後にそれをしたとき、私は小さな記録を持っていて、私は隣人が欲しい高い可能性がありました。ディスクから大きなブロックを読み取ることは一般にほとんど費用がかからないため、1つのレコードが必要な場合は、キャッシュに1000を読み取ります。私の記録はほぼ確実に隣り合っていました。SQLを使用すると、ディスクヘッドはあちこちで跳ね返ります。
ローレンペクテル14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.