web-dev-qa-db-ja.com

「バイナリ」ファイルと「テキスト」ファイルを区別するにはどうすればよいですか?

非公式には、「バイナリ」ファイル(オブジェクトファイル、画像、ムービー、実行可能ファイル、独自のドキュメント形式など)と「テキスト」ファイル(ソースコード、XMLファイル、HTMLファイル、電子メールなど)があることをほとんどの人が理解しています。

一般に、ファイルの内容を知って、それで何か便利なことができるようにする必要があり、エンコードが「バイナリ」または「テキスト」であれば、その観点を形成する必要はありません。そしてもちろん、ファイルはデータのバイトを保存するだけなので、それらはすべて「バイナリ」であり、「テキスト」はエンコーディングを知らなくても何も意味しません。それでも、「バイナリ」ファイルと「テキスト」ファイルについて話すことは依然として有用ですが、この不正確な定義で誰かを怒らせることを避けるために、私は「恐怖」引用符を使い続けます。

ただし、さまざまなファイルで動作するさまざまなツールがあり、実際には、ファイルが「テキスト」か「バイナリ」かによって異なることをしたいと考えています。この例は、コンソールにデータを出力するツールです。プレーンな「テキスト」は見栄えが良く、便利です。 「バイナリ」データは端末を台無しにし、一般的に見るのに役立ちません。 GNU grepは、コンソールへの一致を出力する必要があるかどうかを判断するときに、少なくともこの区別を使用します。

だから、問題は、ファイルが「テキスト」または「バイナリ」であるかどうかをどのように伝えるのですか?さらに制限することは、ファイルシステムのようなLinuxでどのように伝えますか?私はファイルの「タイプ」を示すファイルシステムのメタデータを知らないので、質問はさらに、ファイルの内容を検査することにより、「テキスト」または「バイナリ」であるかどうかをどのように見分けますか?また、簡単にするために、「テキスト」を、ユーザーのコンソールで印刷可能な文字を意味するように制限できます。そして特にimplement thisはどうでしょうか? (これはこのサイトで暗示されていると思いましたが、一般的に、これを行う既存のコードを指すと役立つと思います、私は指定する必要がありました)、私は実際に既存のプログラムを使用して何ができるこの。

59
benno

私の会社のスプレッドシートソフトウェアは、テキストファイルだけでなく、多くのバイナリファイル形式を読み取ります。

まず、最初の数バイトで マジックナンバー を確認します。読み込んだバイナリタイプのマジックナンバーを認識できない場合は、ファイルの最初の2Kバイトまでを調べて、 TF-8 、-であるかどうかを確認します。 TF-16 またはホストオペレーティングシステムの現在の コードページ でエンコードされたテキストファイル。これらのテストのいずれにも合格しなかった場合、処理できるファイルではないと想定し、適切な例外をスローします。

13
Joe Erickson

fileコマンドを使用できます。ファイルに対して一連のテストを実行します(man file)バイナリかテキストかを決定します。 Cからソースコードを実行する必要がある場合は、ソースコードを参照/借用できます。

file README
README: ASCII English text, with very long lines

file /bin/bash
/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
62
naumcho

ファイルの MIMEタイプ を決定できます

file --mime FILENAME

略記は、Linuxではfile -i、macOSではfile -I(大文字のi)です(コメントを参照)。

text/で始まる場合はテキスト、それ以外の場合はバイナリです。唯一の例外はXMLアプリケーションです。ファイルタイプの最後で+xmlを検索することで、それらを一致させることができます。

14
phihag

さて、ファイル全体を調べているだけなら、すべての文字がisprint(c)で印刷可能かどうかを確認してください。 Unicodeではもう少し複雑になります。

Unicodeテキストファイルを区別するために、 MSDNは何をすべきかについて素晴らしいアドバイスを提供します

その要点は、最初の4バイトまでを最初に検査することです。

_EF BB BF     UTF-8 
FF FE        UTF-16, little endian 
FE FF        UTF-16, big endian 
FF FE 00 00  UTF-32, little endian 
00 00 FE FF  UTF-32, big-endian 
_

これでエンコーディングがわかります。次に、テキストファイルの残りの文字にiswprint(c)を使用します。 UTF-8およびUTF-16の場合、単一の文字を可変バイト数で表すことができるため、データを手動で解析する必要があります。また、もしあなたが本当にアナルなら、あなたのプラットフォームで利用可能であれば、iswprintのロケールバリアントを使用したいと思うでしょう。

3
MSN

Perlにはまともなヒューリスティックがあります。使用 -B演算子でバイナリをテストします(その反対の-Tテキストをテストします)。テキストファイルを一覧表示する1行のシェルを次に示します。

$ find . -type f -print0 | Perl -0nE 'say if -f and -s _ and -T _'

(先行ドルなしのアンダースコアは正しいことに注意してください(RTFM)。)

3
bobbogo

現在のdir/subdirsのテキストファイル名を一覧表示するには:

$ grep -rIl ''

バイナリ:

$ grep -rIL ''

特定のファイルを確認するには、コマンドをわずかに変更します。

$ grep -qI '' FILE

次に、終了ステータス「0」は、ファイルがテキストであることを意味します。 '1'-バイナリ。確認できました:

$ echo $?

2
bam

それは古いトピックですが、おそらく誰かがこれを役に立つと思うでしょう。何かがファイルかどうかをスクリプトで決定する必要がある場合は、次のようにできます。

if file -i $1 | grep -q text;
then 
.
.
fi

これはファイルの種類を取得し、サイレントgrepを使用して、そのテキストかどうかを判断できます。

2
VDave

違いを認識しようとするほとんどのプログラムは、ファイルの最初のnバイトを調べて、それらのバイトall「テキスト」として修飾するかどうか(つまり、すべて印刷可能ASCII文字)の範囲内に収まりますか。UNIXライクなシステムでは、より細かく区別するために 'file'コマンドが常にあります。 。

2
dwc

1つの簡単なチェックは、\0文字。テキストファイルにはありません。

1
Georg Schölly

前述のとおり、* nixオペレーティングシステムには、fileコマンド内にこの機能があります。このコマンドは、多くの一般的なファイル構造に含まれるマジックナンバーを定義する構成ファイルを使用します。

このファイルはマジックと呼ばれ、歴史的には/ etcに保存されていましたが、一部のディストリビューションでは/ usr/shareに存在する場合があります。マジックファイルは、ファイル内に存在することがわかっている値のオフセットを定義し、これらの場所を調べてファイルのタイプを判別できます。

マジックファイルの構造と説明は、関連するマニュアルページを参照して見つけることができます(man magic)

実装に関しては、 file.c 自体の中にありますが、読み取り可能なテキストかどうかを判断するファイルコマンドの関連部分は次のとおりです。

/* Make sure we are dealing with ascii text before looking for tokens */
    for (i = 0; i < nbytes - 1; i++) {
        if (!isascii(buf[i]) ||
            (iscntrl(buf[i]) && !isspace(buf[i]) &&
             buf[i] != '\b' && buf[i] != '\032' && buf[i] != '\033'
            )
           )
            return 0;   /* not all ASCII */
    }
1
Steve Weet

Unix libmagicコマンドラインのライブラリバージョンであるfileを使用できます。

多くの言語のラッパーがあります。

1
Benoit Blanchon