web-dev-qa-db-fra.com

Comment distinguer les fichiers «binaires» et «texte»?

De manière informelle, la plupart d'entre nous comprenons qu'il existe des fichiers `` binaires '' (fichiers objets, images, films, exécutables, formats de documents propriétaires, etc.) et des fichiers `` texte '' (code source, fichiers XML, fichiers HTML, e-mail, etc.).

En général, vous devez connaître le contenu d'un fichier pour pouvoir faire quoi que ce soit d'utile et former ce point de vue si l'encodage est "binaire" ou "texte", cela n'a pas vraiment d'importance. Et bien sûr, les fichiers stockent juste des octets de données afin qu'ils soient tous "binaires" et "texte" ne signifie rien sans connaître l'encodage. Et pourtant, il est toujours utile de parler de fichiers "binaires" et "texte", mais pour éviter d'offenser quiconque avec cette définition imprécise, je continuerai à utiliser des guillemets "effrayants".

Cependant, il existe divers outils qui fonctionnent sur un large éventail de fichiers, et en termes pratiques, vous voulez faire quelque chose de différent selon que le fichier est "texte" ou "binaire". Un exemple de cela est tout outil qui génère des données sur la console. Un "texte" clair aura l'air bien et est utile. les données "binaires" gâchent votre terminal et ne sont généralement pas utiles à regarder. GNU grep utilise au moins cette distinction pour déterminer s'il doit afficher des correspondances sur la console.

Alors, la question est, comment savoir si un fichier est "texte" ou "binaire"? Et restreindre est plus loin, comment pouvez-vous le dire sur un système de fichiers de type Linux? Je ne connais aucune métadonnée de système de fichiers qui indique le "type" d'un fichier, donc la question devient, en inspectant le contenu d'un fichier, comment savoir s'il s'agit de "texte" ou "binaire"? Et pour simplifier, permet de restreindre le "texte" aux caractères pouvant être imprimés sur la console de l'utilisateur. Et en particulier, comment feriez-vous implémenter cela? (Je pensais que c'était implicite sur ce site, mais je suppose qu'il est utile, en général, de pointer du code existant qui fait cela, j'aurais dû le préciser), je ne suis pas vraiment après quels programmes existants puis-je utiliser pour faire cette.

59
benno

Le tableur de mon entreprise lit un certain nombre de formats de fichiers binaires ainsi que des fichiers texte.

Nous regardons d'abord les premiers octets pour un nombre magique que nous reconnaissons. Si nous ne reconnaissons le nombre magique d'aucun des types binaires que nous lisons, nous examinons les 2 premiers octets du fichier pour voir s'il semble être un TF-8 , - TF-16 ou un fichier texte codé dans le page de codes actuel du système d'exploitation hôte. S'il ne réussit aucun de ces tests, nous supposons que ce n'est pas un fichier que nous pouvons traiter et lever une exception appropriée.

13
Joe Erickson

Vous pouvez utiliser la commande file. Il fait un tas de tests sur le fichier (man file) pour décider si c'est binaire ou texte. Vous pouvez consulter/emprunter son code source si vous devez le faire à partir de 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

Vous pouvez déterminer le type MIME du fichier avec

file --mime FILENAME

La sténographie est file -i sous Linux et file -I (majuscule i) sur macOS (voir commentaires).

S'il commence par text/, c'est du texte, sinon binaire. La seule exception concerne les applications XML. Vous pouvez faire correspondre ceux-ci en recherchant +xml à la fin du type de fichier.

14
phihag

Eh bien, si vous inspectez tout le fichier, voyez si chaque caractère est imprimable avec isprint(c). Cela devient un peu plus compliqué pour Unicode.

Pour distinguer un fichier texte unicode, MSDN offre d'excellents conseils sur ce qu'il faut faire .

L'essentiel est d'inspecter d'abord les quatre premiers octets:

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 

Cela vous dira l'encodage. Ensuite, vous souhaitez utiliser iswprint(c) pour le reste des caractères du fichier texte. Pour UTF-8 et UTF-16, vous devez analyser les données manuellement car un seul caractère peut être représenté par un nombre variable d'octets. De plus, si vous êtes vraiment anal, vous voudrez utiliser la variante locale de iswprint si elle est disponible sur votre plate-forme.

3
MSN

Perl a une heuristique décente. Utilisez le -B opérateur pour tester le binaire (et son opposé, -T pour tester le texte). Voici Shell une ligne pour répertorier les fichiers texte:

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

(Notez que les caractères de soulignement sans dollar précédent sont corrects (RTFM).)

3
bobbogo

Pour répertorier les noms de fichiers texte dans les répertoires/sous-répertoires actuels:

$ grep -rIl ''

Binaires:

$ grep -rIL ''

Pour vérifier un fichier particulier, modifiez légèrement la commande:

$ grep -qI '' FILE

puis, l'état de sortie "0" signifierait que le fichier est un texte; "1" - binaire. Pourrait vérifier:

$ echo $?

2
bam

C'est un vieux sujet, mais peut-être que quelqu'un trouvera cela utile. Si vous devez décider dans un script si quelque chose est un fichier, vous pouvez simplement faire comme ceci:

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

Cela obtiendra le type de fichier, et avec un grep silencieux, vous pouvez décider si c'est un texte.

2
VDave

La plupart des programmes qui essaient de faire la différence utilisent une heuristique, comme examiner les premiers n octets du fichier et voir si ces octets tous peut être qualifié de 'texte' ou non (c.-à-d. est-ce qu'ils entrent tous dans la plage des caractères ASCII) imprimables. Pour une distension plus fine, il y a toujours la commande 'file' sur les systèmes de type UNIX .

2
dwc

Une simple vérification est de savoir si elle a \0 personnages. Les fichiers texte n'en ont pas.

1
Georg Schölly

Comme indiqué précédemment, les systèmes d'exploitation * nix ont cette capacité dans la commande file. Cette commande utilise un fichier de configuration qui définit les nombres magiques contenus dans de nombreuses structures de fichiers populaires.

Ce fichier, appelé magic, était historiquement stocké dans/etc, bien qu'il puisse être dans/usr/share sur certaines distributions. Le fichier magique définit les décalages de valeurs connues pour exister dans le fichier et peut ensuite examiner ces emplacements pour déterminer le type du fichier.

La structure et la description du fichier magique peuvent être trouvées en consultant la page de manuel correspondante (man magic)

En ce qui concerne une implémentation, bien que l'on puisse trouver dans file.c lui-même, cependant la partie pertinente de la commande file qui détermine s'il s'agit de texte lisible ou non est la suivante

/* 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

Vous pouvez utiliser libmagic qui est une version bibliothèque de la ligne de commande Unix file.

Il existe des wrappers pour de nombreuses langues:

1
Benoit Blanchon