Comment puis-je savoir si un fichier est binaire (non textuel) en python?
Je recherche dans un grand nombre de fichiers en python et continue à obtenir des correspondances dans des fichiers binaires. Cela rend la sortie incroyablement désordonnée.
Je sais que je pourrais utiliser grep -I
, mais je fais plus avec les données que ce que permet grep.
Dans le passé, j'aurais simplement cherché des personnages plus grands que 0x7f
, mais utf8
et autres, cela rendait cela impossible sur les systèmes modernes. Idéalement, la solution serait rapide, mais n'importe quelle solution fera l'affaire.
grep
utilisée pour identifier les fichiers binaires est similaire à celle publiée par Jorge Orpinel ci-dessous . Sauf si vous définissez l'-z
option, il recherchera simplement un caractère nul ("\000"
) dans le fichier. Avec-z
, il recherche"\200"
. Les personnes intéressées et / ou sceptiques peuvent consulter la ligne 1126 degrep.c
. Désolé, je n'ai pas trouvé de page Web avec le code source, mais vous pouvez bien sûr l'obtenir à partir de gnu.org ou via une distribution .git diff
GNU et GNUdiff
utilisent également la même stratégie. Je ne sais pas si c'est si répandu parce que c'est tellement plus rapide et plus facile que l'alternative, ou si c'est simplement à cause de la rareté relative des fichiers UTF-16 sur les systèmes qui ont tendance à avoir ces utilitaires installés.Réponses:
Vous pouvez également utiliser le module mimetypes :
Il est assez facile de compiler une liste de types binaires mime. Par exemple, Apache distribue un fichier mime.types que vous pouvez analyser dans un ensemble de listes, binaires et texte, puis vérifier si le mime est dans votre liste de texte ou de binaire.
la source
mimetypes
utiliser le contenu d'un fichier plutôt que simplement son nom?file
rapporte comme "texte Unicode UTF-8, avec de très longues lignes" mais mimetypes.gest_type () retournera (None, None). De plus, la liste des types MIME d'Apache est une liste blanche / un sous-ensemble. Ce n'est en aucun cas une liste complète des types MIME. Il ne peut pas être utilisé pour classer tous les fichiers en tant que texte ou non-texte.Encore une autre méthode basée sur le comportement de file (1) :
Exemple:
la source
bytearray([7,8,9,10,12,13,27]) + bytearray(range(0x20, 0x7f)) + bytearray(range(0x80, 0x100))
place. Voir Python, fichier (1) - Pourquoi les nombres [7,8,9,10,12,13,27] et la plage (0x20, 0x100) sont-ils utilisés pour déterminer le texte par rapport au fichier binaire et github.com/file/file/ blob /…0x7f
(DEL
).11
ouVT
? Dans le tableau 11 est considéré comme du texte ASCII brut, et c'est levertical tab
.Si vous utilisez python3 avec utf-8, c'est simple, ouvrez simplement le fichier en mode texte et arrêtez le traitement si vous obtenez un fichier
UnicodeDecodeError
. Python3 utilisera unicode lors de la gestion des fichiers en mode texte (et bytearray en mode binaire) - si votre encodage ne peut pas décoder des fichiers arbitraires, il est fort probable que vous obteniezUnicodeDecodeError
.Exemple:
la source
with open(filename, 'r', encoding='utf-8') as f
directement?Si cela aide, de nombreux types binaires commencent par des nombres magiques. Voici une liste de signatures de fichiers.
la source
Essaye ça:
la source
git diff
fait de cette façon , et bien sûr, il détecte les fichiers UTF-16 comme binaires.diff
fonctionne également de cette façon. Il a des problèmes similaires avec les fichiers UTF-16.file
détecte correctement les mêmes fichiers que le texte UTF-16. Je n'ai pas extraitgrep
le code de, mais il détecte aussi les fichiers UTF-16 comme binaires.file(1)
laquelle il n'est pas sûr d'imprimer sans conversion, donc cette méthode est appropriée dans ce cas.Voici une suggestion qui utilise la commande de fichier Unix :
Exemple d'utilisation:
Il a les inconvénients de ne pas être portable sur Windows (à moins que vous n'ayez quelque chose comme la
file
commande là-bas) et de devoir générer un processus externe pour chaque fichier, ce qui peut ne pas être acceptable.la source
file
"Configuration gelée de Sendmail - version m" - notez l'absence de la chaîne "texte". Peut-être utiliserfile -i
?Utilisez la bibliothèque binaryornot ( GitHub ).
C'est très simple et basé sur le code trouvé dans cette question stackoverflow.
Vous pouvez en fait l'écrire en 2 lignes de code, mais ce package vous évite d'avoir à écrire et à tester minutieusement ces 2 lignes de code avec toutes sortes de types de fichiers étranges, multiplateformes.
la source
Habituellement, vous devez deviner.
Vous pouvez regarder les extensions comme un indice, si les fichiers en ont.
Vous pouvez également reconnaître les formats binaires connus et les ignorer.
Sinon, voyez quelle proportion d'octets ASCII non imprimables vous avez et faites une estimation à partir de cela.
Vous pouvez également essayer le décodage à partir de UTF-8 et voir si cela produit une sortie sensible.
la source
Une solution plus courte, avec un avertissement UTF-16:
la source
for line in file
peut consommer une quantité illimitée de mémoire jusqu'à ce qu'ilb'\n'
soit trouvé".read()"
retourne un bytestring ici qui est itérable (il donne octets individuels).Nous pouvons utiliser python lui-même pour vérifier si un fichier est binaire, car il échoue si nous essayons d'ouvrir un fichier binaire en mode texte
la source
Si vous n'êtes pas sous Windows, vous pouvez utiliser Python Magic pour déterminer le type de fichier. Ensuite, vous pouvez vérifier s'il s'agit d'un type texte / mime.
la source
Voici une fonction qui vérifie d'abord si le fichier commence par une nomenclature et sinon recherche un octet de zéro dans les 8192 octets initiaux:
Techniquement, la vérification de la nomenclature UTF-8 n'est pas nécessaire car elle ne doit pas contenir zéro octet dans tous les cas pratiques. Mais comme il s'agit d'un encodage très courant, il est plus rapide de vérifier la nomenclature au début au lieu de balayer tous les 8192 octets pour 0.
la source
Essayez d'utiliser le python-magic actuellement maintenu qui n'est pas le même module dans la réponse de @Kami Kisiel. Cela prend en charge toutes les plates-formes, y compris Windows, mais vous aurez besoin des
libmagic
fichiers binaires. Ceci est expliqué dans le README.Contrairement au module mimetypes , il n'utilise pas l'extension du fichier et inspecte à la place le contenu du fichier.
la source
Je suis venu ici à la recherche exactement de la même chose - une solution complète fournie par la bibliothèque standard pour détecter le binaire ou le texte. Après avoir examiné les options suggérées par les gens, la commande de fichier nix semble être le meilleur choix (je ne développe que pour linux boxen). Certains autres ont publié des solutions à l'aide de fichiers, mais elles sont inutilement compliquées à mon avis, alors voici ce que j'ai proposé:
Cela devrait aller de soi, mais votre code qui appelle cette fonction doit s'assurer que vous pouvez lire un fichier avant de le tester, sinon cela détectera par erreur le fichier comme binaire.
la source
Je suppose que la meilleure solution est d'utiliser la fonction guess_type. Il contient une liste avec plusieurs types MIME et vous pouvez également inclure vos propres types. Voici le script que j'ai fait pour résoudre mon problème:
Il se trouve à l'intérieur d'une classe, comme vous pouvez le voir en fonction de la structure du code. Mais vous pouvez pratiquement changer les choses que vous souhaitez implémenter dans votre application. C'est assez simple à utiliser. La méthode getTextFiles retourne un objet de liste avec tous les fichiers texte qui résident dans le répertoire que vous passez dans la variable de chemin.
la source
sur * NIX:
Si vous avez accès à la
file
commande shell, shlex peut aider à rendre le module de sous-processus plus utilisable:Ou, vous pouvez également coller cela dans une boucle for pour obtenir la sortie de tous les fichiers dans le répertoire actuel en utilisant:
ou pour tous les sous-répertoires:
la source
La plupart des programmes considèrent que le fichier est binaire (c'est-à-dire tout fichier qui n'est pas "orienté ligne") s'il contient un caractère NULL .
Voici la version de perl de
pp_fttext()
(pp_sys.c
) implémentée en Python:Source: Perl "suppose si le fichier est du texte ou du binaire" implémenté en Python
la source
êtes-vous sous Unix? si c'est le cas, essayez:
Les valeurs de retour du shell sont inversées (0 est ok, donc s'il trouve "text" alors il retournera un 0, et en Python c'est une expression False).
la source
file
avec le-b
commutateur; il n'imprimera que le type de fichier sans le chemin.is_binary_file = lambda filename: "text" in subprocess.check_output(["file", "-b", filename])
Un moyen plus simple est de vérifier si le fichier est composé de caractères NULL (
\x00
) en utilisant l'in
opérateur, par exemple:Voir ci-dessous l'exemple complet:
Exemple d'utilisation:
la source
Documentation
la source