多くのプロジェクトで、データ オブジェクト/構造がバイナリ モードでファイルに書き込まれ、バイナリ モードでファイルから再び取得されることがわかりました。
なぜ彼らはバイナリモードでそれを行うのだろうか? テキスト モードとバイナリ モードのパフォーマンスの違いはありますか? そうでない場合、いつバイナリモードまたはテキストモードを使用するのですか?
バイナリの方が高速です。123456 のように、32 ビット (4 バイト) で格納された整数を考えてみましょう。これをバイナリ (コンピューターでの表現方法) として書き出す場合、4 バイトかかります (構造内の位置合わせのためにアイテム間のパディングを無視します)。 )。
数値をテキストとして書き込むには、文字列に変換し (変換するためのオーバーヘッドと格納するためのメモリが必要です)、書き出す必要があります。数値を表すのに 6 文字あるため、少なくとも 6 バイトかかります。これには、配置用のスペースやデータの読み取り/分離用の区切り文字などの追加のパディングは含まれません。
数千のアイテムがあると考えると、追加の時間が追加され、より多くのスペースが必要になる可能性があります。これにより、読み取りに時間がかかり、値を読み取った後にストレージ用にバイナリに変換するための追加の時間が発生します。メモリに。
テキストの利点は、バイナリ データやデータの 16 進ダンプを読み取ろうとするよりも、はるかに読みやすいことです。
歴史的に、バイナリ モードは、基になるストリームへの多かれ少なかれ透過的なアクセスを提供することです。テキストモードは標準のテキスト表現に「正規化」し、行は単一の'\n'
キャラクター。さらに、システムはバイナリ ファイルのサイズに制限を課す場合があります。たとえば、128 バイトまたは 512 バイトの倍数にする必要があります。(1 つ目は CP/M の場合で、多くの DEC OS の 2 つ目です。) テキスト ファイルにはこの制限がなく、OS がそれを課した場合、ライブラリは通常、追加のファイル終了文字を導入します。テキストファイル用。(今日でも、ほとんどの Windows ライブラリは、テキスト モードでの読み取り時に古い CP/M エンド オブ ファイル 0x1A を認識します。) これらの考慮事項により、テキスト モードは限られた一連のバイナリ値でのみ定義されます。(ただし、バイナリ ファイルに 200 バイトを書き込むと、再度読み取ると 256 または 512 が返される場合があります。歴史的に、バイナリは、論理的な終わりを認識できるように、構造化されていないテキストにのみ使用する必要があります。
また、バイナリ モードで開いたファイルをほぼ任意にシークできます。テキストモードでは、先頭または以前に記憶した位置にのみシークできます。(これは、行末マッピングが、ファイル内の位置とテキスト ストリーム内の位置の間に単純な関係がないことを意味するためです。)
これは、出力がフォーマットされているかどうかと直交していることに注意してください: を使用して出力<<
(および を使用して入力>>
) すると、ファイルが開かれたモードに関係なく、IO がフォーマットされます。フォーマットは常にテキストです。iostream は、テキストのストリームを操作するように設計されており、テキスト以外の入出力のサポートは限定されています。
今日、状況は少し変わりました。多くの場合、私たちは自分が書いたものを他のマシンから読み取ることができると期待しています。これは、適切に定義された形式を前提としていますが、ネイティブで使用されている形式ではない可能性があります。(したがって、たとえば、インターネットでは、2 バイト シーケンス 0x0D、0x0A が行末として想定されます。これは、Unix や他の多くの OS で内部的に使用されるものとは異なります。) 移植性が懸念される場合は、通常、フォーマットを定義します。明示的に記述し、バイナリ モードを使用して、記述内容が正確に記述されていることを確認します。同様に、入力ではバイナリ形式を使用し、規則を手動で処理します。ただし、共有されていないローカル ディスクに書き込むだけの場合は、テキスト モードで問題なく、作業量が少し少なくなります。
繰り返しますが、これらは両方ともテキストに適用されます。バイナリ形式が必要な場合は、バイナリ モードを使用する必要がありますが、それだけでは不十分です。フォーマットされたすべての IO を自分で実装する必要があります。std::istream
そのような場合、私は通常or (抽象化はテキストです) を使用しませんが、
(エラー処理規則のために)std::ostream
派生し、 (物理 IO のために) 使用する、独自のストリーム タイプを定義します。std::ios_base
std::streambuf
最後に、すべての事実を無視しないでください。IO は何らかの方法でフォーマットされています。メモリのブロックをファイルに書き出すだけで、現在の実装がたまたま提供する形式と同じであることを意味します (これは一般的に文書化されていないため、おそらく将来的には読み取ることができなくなります)。あなたがしているのはディスクへのスピルだけであり、それを読むのは同じプログラムで、同じバージョンの同じコンパイラーで同じコンパイラー・オプションを使用してコンパイルされたときだけである場合は、メモリーをダンプすることができます。問題のメモリは POD のみであり、ポインタは含まれていません。それ以外の場合は、使用するフォーマットを定義 (および文書化) し、それを実装する必要があります。そのような場合、独自の形式を発明するよりも、XDR などの既存の形式を使用することをお勧めします。ドキュメントとして「XDR 形式を使用」と書く方がはるかに簡単です。
あなたのプログラムがファイルを使用する唯一のプログラムである場合、バイナリ ファイルを使用して内部構造を「そのまま」保存できます。
ただし、ファイルを他のプログラムと交換したり、インターネット経由で交換したい場合は、バイナリ形式はあまり適していません。たとえば、ビッグ エンディアン マシンとリトルエンディアン マシンの問題について考えてみましょう。また、ファイルやデータの受信者はコードや構造にアクセスできない可能性が高いため、テキストベースの形式の方が解析しやすく、独自の構造に実装できます。
パフォーマンスについては、内部構造を直接読み書きする方が高速であることは事実です。これは、内部構造を別の形式に変換 (マーシャリングとも呼ばれます) する必要がないためです。
テキストモードでファイルを読み書きする場合は、テキストを操作しています。エンコーディング エラーや OS 固有のフォーマット変更の対象となる可能性がありますが、問題なく動作する場合もあります。ただし、バイナリ モードでは、これらの制限は満たされません。\n
また、テキストモードは、文字を に置き換えるなど、文字で面白いことを行う場合があります\n\r
。
たとえば、 Fopenリファレンスは次のように述べています。
テキスト ファイルの場合、アプリケーションが実行される環境によっては、システム固有のテキスト ファイル形式に適合させるために、入出力操作で特殊文字の変換が行われる場合があります。ほとんどの UNIX ベースのシステムなど、多くの環境では、ファイルをテキスト ファイルとして開いてもバイナリ ファイルとして開いても違いはありません。どちらもまったく同じように扱われますが、移植性を高めるために区別することをお勧めします。
バイナリモードでは、使用するバイトサイズ(256を考慮)があり、テキストモードでは100文字を超えることはほとんどありません。明らかに、データを保存するために2倍以上のサイズが得られます。
さらに、IPv4のようなネットワークパケットなどの構造仕様に従わなければならない場合があります。
例を見てみましょう
//No padding
typedef struct abc
{
int a:4
char b;
double c;
} A[]={{.a=4,.b='a',.c=7.45},{.a=24,.b='z',.c=3.2}} ;
ビットフィールドをテキストモードで保存するのは難しいことではありません。明らかに、多くのことを失うことになります。
ただし、MIMEを使用した場合と同様に、データオブジェクトをテキスト形式で保存できますが、バイナリモードで変換するには追加のルーチンが必要になります。パフォーマンスが打たれました。
バイナリ モードとテキスト モードの選択によって影響を受けるオペレーティング システムはごくわずかです。Unix または Linux システムのいずれも、テキスト モードに対して特別なことを行いません。つまり、テキストはバイナリと同じです。
特に Windows と VMS は、テキスト モードでデータを変換します。Windowsは、ファイルに書き込むときは に変換\n
し、読み取るときはその逆に変換します。\r\n
VMS には監視対象のファイル レコード構造があるため、デフォルト モードで\n
はレコード区切り文字に変換されます。
異なるところは、バイナリの方が高速です。違いがなければ、違いはありません。
バイナリ形式は、正確な内部表現で格納されるため、数値を格納するのにより正確です。データの保存中に会話がないため、保存がはるかに高速です。