2009-09-18 39 views
13

Necesito identificar qué archivo es binario y que es texto en un directorio.¿Cómo identificar archivos binarios y de texto usando Python?

Intenté utilizar mimetypes pero no es una buena idea en mi caso porque no puede identificar todos los archivos mimos, y tengo extraños aquí ... Solo necesito saber, binario o texto. Sencillo ? Pero no pude encontrar una solución ...

Gracias

+2

¿Qué es un archivo de texto para usted? ¿UTF-16-BE codifica el conteo Unicode, por ejemplo? –

+3

Debe definir con precisión lo que significa 'binario' y 'texto' antes de que nadie pueda ayudarlo. –

+0

El archivo de texto es cualquier archivo legible por humanos. Digamos, cualquier archivo que pueda leer con un comando "cat" (linux) o "type" (windows). – Thomas

Respuesta

9

Gracias a todos, encontré una solución que se adaptaba a mi problema. Encontré este código en http://code.activestate.com/recipes/173220/ y cambié solo una pequeña pieza para mí.

Funciona bien.

from __future__ import division 
import string 

def istext(filename): 
    s=open(filename).read(512) 
    text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b")) 
    _null_trans = string.maketrans("", "") 
    if not s: 
     # Empty files are considered text 
     return True 
    if "\0" in s: 
     # Files with null bytes are likely binary 
     return False 
    # Get the non-text characters (maps a character to itself then 
    # use the 'remove' option to get rid of the text characters.) 
    t = s.translate(_null_trans, text_characters) 
    # If more than 30% non-text characters, then 
    # this is considered a binary file 
    if float(len(t))/float(len(s)) > 0.30: 
     return False 
    return True 
+7

Una pequeña corrección para su código: 'if float (len (t))/float (len (s))> 0.30: return 0' De lo contrario, python usará la división entera, y la comparación solo será verdadera cuando len (t) == len (s) –

+1

Thomas, ¡aplique esa corrección de "flotante" a la respuesta! ¡Activestate también debería arreglar su receta! ;) pero no me puedo molestar en registrarme para comentar los comentarios allí. –

+0

también hay un seguimiento * en la última línea, no debería estar allí –

4

Si se ejecuta un script en * nix, usted podría utilizar algo como esto:

import subprocess 
import re 

def is_text(fn): 
    msg = subprocess.Popen(["file", fn], stdout=subprocess.PIPE).communicate()[0] 
    return re.search('text', msg) != None 
+0

No hay necesidad de 're' si solo está buscando una subcadena. –

+0

No funciona si 'text' es parte de la ruta de archivo del archivo binario. – Paddre

+1

Sugiero Popen (["archivo", "--mime", fn]. ...). De lo contrario, la palabra "texto" podría no aparecer. En mi Linux, la respuesta para algo que se parece a un programa Fortran es "FORTAN program". Si agrega el modificador de mimo, obtendrá "text/x-fortran; charset = us-ascii". – Tsf

7

Es inherentemente no sencilla. No hay forma de saberlo con certeza, aunque puede adivinar razonablemente bien en la mayoría de los casos.

cosas que le gustaría hacer:

  • Busque números mágicos conocidos en firmas binarias
  • Busca el orden de bytes-marca de Unicode en el inicio del archivo
  • Si el archivo es regularmente 00 xx 00 xx 00 xx (para arbitrario xx) o viceversa, posiblemente sea UTF-16
  • De lo contrario, busque 0 en el archivo; un archivo con un 0 en es poco probable para ser un archivo de texto de codificación de un solo byte.

pero es todo heurística - es muy posible tener un archivo que es un archivo de texto válido y un archivo de imagen válido, por ejemplo. Probablemente sería una tontería como un archivo de texto, pero legítimo en alguna codificación u otra ...

4

Podría ser posible utilizar libmagic adivinar el tipo MIME del archivo usando python-magic. Si recupera algo en el espacio de nombre "text/*", es probable que sea un archivo de texto, mientras que cualquier otra cosa es probable que sea binary file.

Cuestiones relacionadas