C ++を使用して、ファイルの内容がASCIIまたはバイナリであるとどのように識別しますか?
11 に答える
ファイルに10 進バイトの 9 ~ 13、32 ~ 126のみが含まれている場合、それはおそらく純粋な ASCII テキスト ファイルです。そうでなければ、そうではありません。ただし、別のエンコーディングのテキストである可能性もあります。
上記のバイトに加えて、ファイルに 10 進数のバイト 128 ~ 255のみが含まれている場合、それはおそらく、ISO-8859-1、UTF-8、またはアスキー + Big5。そうでない場合は、目的によってはここで停止して、ファイルをバイナリと見なすことができる場合があります。ただし、16 ビットまたは 32 ビット エンコーディングのテキストである場合もあります。
ファイルが上記の制約を満たしていない場合は、ファイルの最初の 2 ~ 4 バイトでバイトオーダー マークを調べます。
- 最初の 2 バイトが hex の
FE FF
場合、ファイルは暫定的にUTF-16 BE です。 - 最初の 2 バイトが hex
FF FE
で、次の 2 バイトがhexでない00 00
場合、ファイルは暫定的にUTF-16 LE です。 - 最初の 4 バイトが hex の
00 00 FE FF
場合、ファイルは暫定的にUTF-32 BE です。 - 最初の 4 バイトが hex の
FF FE 00 00
場合、ファイルは暫定的にUTF-32 LE です。
上記のチェックで暫定的なエンコーディングを決定した場合は、以下の対応するエンコーディングのみをチェックして、ファイルがたまたまバイトオーダー マークと一致するバイナリ ファイルではないことを確認します。
一時的なエンコーディングを決定していない場合でも、ファイルはこれらのエンコーディングのいずれかのテキスト ファイルである可能性があります。バイト オーダー マークは必須ではないため、次のリストですべてのエンコーディングを確認してください。
- ファイルに10 進値が 9 ~ 13、32 ~ 126、および 128 以上のビッグ エンディアンの 2 バイト ワードのみが含まれている場合、そのファイルはおそらく UTF-16 BE です。
- ファイルに10 進値が 9 ~ 13、32 ~ 126、および 128 以上のリトル エンディアンの 2 バイト ワードのみが含まれている場合、そのファイルはおそらく UTF-16 LE です。
- ファイルに10 進値が 9 ~ 13、32 ~ 126、および 128 以上のビッグ エンディアンの 4 バイト ワードのみが含まれている場合、そのファイルはおそらく UTF-32 BE です。
- ファイルに10 進値が 9 ~ 13、32 ~ 126、および 128 以上のリトル エンディアンの 4 バイト ワードのみが含まれている場合、そのファイルはおそらく UTF-32 LE です。
これらすべてのチェックを行ってもエンコーディングが決定されない場合、そのファイルは私が知っている ASCII ベースのエンコーディングのテキスト ファイルではないため、ほとんどの場合、おそらくバイナリと見なすことができます (まだEBCDIC などの非 ASCII エンコーディングのテキスト ファイルである必要がありますが、それは問題の範囲外であると思われます)。
stream.get()で通常のループを使用して反復処理し、読み取ったバイト値がであるかどうかを確認します<= 127
。それを行うための多くの方法の1つの方法:
int c;
std::ifstream a("file.txt");
while((c = a.get()) != EOF && c <= 127)
;
if(c == EOF) {
/* file is all ASCII */
}
しかし、誰かが言ったように、すべてのファイルは結局のところバイナリファイルです。さらに、「ASCII」が何を意味するのかは明確ではありません。あなたが文字コードを意味するならば、それから確かにこれはあなたが行く方法です。ただし、英数字の値のみを意味する場合は、別の方法が必要になります。
私のテキスト エディターは、null バイトの存在を判断します。実際には、これは非常にうまく機能します。null バイトのないバイナリ ファイルは非常にまれです。
すべてのファイルの内容はバイナリです。だから、他に何も知らないので、あなたは確信が持てません。
ASCIIは解釈の問題です。テキストエディタでバイナリファイルを開くと、私が何を意味しているのかがわかります。
ほとんどのバイナリファイルには、検索できる固定ヘッダー(タイプごと)が含まれています。または、ファイル拡張子をヒントとして使用することもできます。UTFでエンコードされたファイルが必要な場合は、バイト順マークを探すことができますが、それらもオプションです。
質問をより厳密に定義しない限り、決定的な答えはありません。
質問が純粋に ASCII だけを検出する方法である場合、litb の答えは的を射ています。ただし、san がファイルにテキストが含まれているかどうかを判断する方法を知っていた場合、問題はさらに複雑になります。ASCII は、テキストを表現する方法の 1 つにすぎません (ますます人気がなくなりつつあります)。Unicode システム - UTF16、UTF32、および UTF8 の人気が高まっています。理論的には、最初の 2 バイトが Unicocde バイト オーダー マーク (BOM) 0xFEFF (またはバイト オーダーが逆の場合は 0xFFFE) であるかどうかを確認することで、これらを簡単にテストできます。ただし、これらの 2 バイトは Linux システムの多くのファイル形式を台無しにするため、そこに存在することを保証することはできません。さらに、バイナリ ファイルは 0xFEFF で始まる場合があります。
ファイルがユニコードの場合、0x00 (または他の制御文字) を探しても役に立ちません。ファイルがたとえば UFT16 で、ファイルに英語のテキストが含まれている場合、1 文字おきに 0x00 になります。
テキスト ファイルが書き込まれる言語がわかっている場合は、バイトを分析して、テキストが含まれているかどうかを統計的に判断できます。たとえば、英語で最も一般的な文字は E の後に T が続きます。したがって、ファイルに Z と X よりも E と T が多く含まれている場合、それはおそらくテキストです。もちろん、これを ASCII およびさまざまな Unicode としてテストして確認する必要があります。
ファイルが英語で書かれていない場合、または複数の言語をサポートしたい場合は、Windows でファイル拡張子を確認し、「マジック ファイル」コードのデータベースに対して最初の 4 バイトをチェックして、ファイルのタイプを判別し、テキストが含まれているかどうかを判別します。
この質問には、正解も不正解もありません。考えられるすべてのテキストファイルで機能しない複雑なソリューションだけです。
これは、メモ帳がASCIIファイルのタイプを検出する方法に関するThe OldNewThingの記事へのリンクです。完璧ではありませんが、Microsoftがそれをどのように処理するかを見るのは興味深いことです。
まあ、これはASCIIの定義に依存します。ASCIIコード<128の値をチェックするか、定義した文字セット(たとえば、「a」-「z」、「A」-「Z」、「0」-「9」...)をチェックして、ファイルを処理できます。他の文字が含まれている場合はバイナリとして。
また、通常の改行(0x10または0x13,0x10)をチェックして、テキストファイルを検出することもできます。
確認するには、ファイルをバイナリとして開く必要があります。ファイルをテキストとして開くことはできません。ASCII は実質的にバイナリのサブセットです。その後、バイト値を確認する必要があります。ASCII のバイト値は 0 ~ 127 ですが、0 ~ 31 は制御文字です。TAB、CR、および LF のみが共通の制御文字です。「A」と「Z」は (移植可能に) 使用できません。それらが ASCII (!) であるという保証はありません。それらが必要な場合は、定義する必要があります。
const unsigned char ASCII_A = 0x41; // NOT 'A'
const unsigned char ASCII_Z = ASCII_A + 25;