2009-02-19 21 views
52

Informalmente, la mayoría de nosotros entiende que hay archivos 'binarios' (archivos de objeto, imágenes, películas, ejecutables, formatos de documento de propiedad, etc.) y archivos 'de texto' (código fuente, archivos XML, HTML, correo electrónico, etc.) .¿Cómo distingo entre archivos 'binarios' y 'texto'?

En general, necesita saber el contenido de un archivo para poder hacer algo útil con él, y formar ese punto de vista si la codificación es 'binaria' o 'texto', en realidad no importa . Y, por supuesto, los archivos solo almacenan bytes de datos para que sean todos 'binarios' y 'texto' no significa nada sin conocer la codificación. Y, sin embargo, todavía es útil hablar sobre archivos 'binarios' y 'de texto', pero para evitar ofender a nadie con esta definición imprecisa, continuaré usando citas 'de susto'.

Sin embargo, hay varias herramientas que funcionan en una amplia gama de archivos, y en términos prácticos, desea hacer algo diferente en función de si el archivo es 'texto' o 'binario'. Un ejemplo de esto es cualquier herramienta que muestre datos en la consola. El 'texto' sencillo se verá bien y es útil. Los datos 'binarios' estropean su terminal y, en general, no son útiles para mirar. GNU grep al menos usa esta distinción para determinar si debería generar coincidencias con la consola.

Entonces, la pregunta es, ¿cómo se puede decir si un archivo es 'texto' o 'binario'? Y para restringir es más, ¿cómo se puede decir en un sistema de archivos como Linux? No conozco ningún metadato del sistema de archivos que indique el "tipo" de un archivo, por lo que la pregunta se vuelve aún más, al inspeccionar el contenido de un archivo, ¿cómo puedo saber si es 'texto' o 'binario'? Y para simplificar, permitamos que "texto" restrinja los caracteres que se pueden imprimir en la consola del usuario. Y en particular, ¿cómo implementaría esto? (Pensé que esto estaba implícito en este sitio, pero creo que es útil, en general, apuntar al código existente que hace esto, debería haberlo especificado), realmente no estoy buscando qué programas existentes puedo usar para hacer esta.

Respuesta

11

Nuestro software lee una cantidad de formatos de archivos binarios y también archivos de texto.

Primero nos fijamos en los primeros bytes de un magic number que reconocemos. Si no reconocemos el número mágico de cualquiera de los tipos binarios que leemos, miraremos hasta los primeros 2K bytes del archivo para ver si parece ser un UTF-8, UTF-16 o un archivo de texto codificado en el actual code page del sistema operativo host. Si no pasa ninguna de estas pruebas, suponemos que no se trata de un archivo que podamos tratar y arroje una excepción adecuada.

+17

no dice qué es "nuestro software", ralentizando el análisis humano. – vwvan

4

Bueno, si solo está inspeccionando el archivo completo, vea si cada carácter es imprimible con isprint(c). Se vuelve un poco más complicado para Unicode.

Para distinguir un archivo de texto Unicode, MSDN offers some great advice as to what to do.

El quid de la cuestión es inspeccionar por primera vez a los cuatro primeros bytes:

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 

que va a decir la codificación. Luego, querrá usar iswprint(c) para el resto de los caracteres en el archivo de texto. Para UTF-8 y UTF-16, debe analizar manualmente los datos, ya que un solo carácter puede representarse mediante un número variable de bytes. Además, si eres realmente anal, querrás usar la variante de configuración regional de iswprint si está disponible en tu plataforma.

+0

Solo funciona con archivos que usan esta regla. –

+0

Bueno, si no sigue esas reglas, entonces realmente no es un archivo de texto. Excepto por mbcs, pero esa es una historia completamente diferente. – MSN

+3

El estándar Unicode no fomenta anteponer una BOM a archivos UTF-8, y es una pena que no lo prohíban directamente. Además, esos otros formatos no necesariamente tienen uno. – Deduplicator

2

mayoría de los programas que tratan de decir la diferencia utilizar una heurística, tales como el examen de las primeras n bytes del archivo y ver si los bytes todo califica como 'texto' o no (es decir, hacer que todos caen dentro del rango de charcters ASCII imprimibles). Para obtener una mejor definición, siempre existe el comando 'file' en los sistemas tipo UNIX.

60

Puede usar el comando file. Hace un montón de pruebas en el archivo (man file) para decidir si es binario o de texto. Puede ver/tomar prestado su código fuente si necesita hacer eso desde 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 
+0

+1 Si se trata de un sistema Linux, el archivo tendrá una heurística mucho mejor que cualquier otra que construya usted mismo. –

+0

Sí, si el archivo está disponible, será la mejor herramienta para el trabajo. ¡No hay duda! También el 'archivo -I' es un buen truco. No había pensado en bombardear para mi problema en particular, sin embargo, no creo que pueda controlar el rendimiento general. ¡Gracias! – benno

10

Se puede determinar el MIME type del archivo con

file --mime 

La taquigrafía es file -i en Linux y file -I (capital i) en MacOS (ver comentarios).

Si comienza con text/, es texto, de lo contrario es binario. La única excepción son las aplicaciones XML. Puede encontrarlos buscando +xml al final del tipo de archivo.

+0

Creo que debería ser "archivo -I" (mayúsculas). Al menos de acuerdo con mis pruebas y mi página de manual. – benno

+1

Acabo de buscarlo, la minúscula es correcta en Debian y gentoo Linux. Su archivo es ftp://ftp.astron.com/pub/file/file-5.00.tar.gz (o una versión diferente). -I (superior) es una opción en ninguno de los dos. – phihag

+0

Huh, raro. La versión en OS X (4.17) utiliza -I (superior) y la de mis cuadros de Linux (4.24) usa -i (inferior). ¡Qué extraño! Me pregunto si se trata de un OS X-ism, o los autores simplemente cambiaron la interfaz entre lanzamiento de punto. – benno

1

Una simple comprobación es si tiene \0 caracteres. Los archivos de texto no los tienen.

+9

a menos que sea utf-16 o utf32. entonces hay muchos. – Breton

1

Como se indicó anteriormente * los sistemas operativos nix tienen esta capacidad dentro del comando de archivo. Este comando usa un archivo de configuración que define números mágicos contenidos en muchas estructuras de archivos populares.

Este archivo, llamado magic, se almacenó históricamente en/etc, aunque puede estar en/usr/share en algunas distribuciones. El archivo mágico define compensaciones de valores conocidos que existen dentro del archivo y luego puede examinar estas ubicaciones para determinar el tipo de archivo.

La estructura y descripción de la magia archivo se puede encontrar consultando la página del manual correspondiente (Magic Man)

En cuanto a la aplicación, así que se pueden encontrar dentro de file.c sí, sin embargo la parte pertinente del archivo El comando que determina si es texto legible o no es el siguiente

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

Perl tiene una heurística decente. Use el operador -B para probar binario (y su opuesto, -T para buscar texto). Aquí de Shell una sola línea a la lista de archivos de texto:

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

(Tenga en cuenta que los guiones sin un dólar precedente son correctos (RTFM).)

2

Es un tema viejo, pero tal vez alguien va a resultar útil . Si usted tiene que decidir en un script si algo es un archivo, entonces puede simplemente hacer como esto:

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

Esto hará que el tipo de archivo, y con un grep silenciosa que puede decidir si es un texto.

+0

osx tiene dos variantes para esto: minúscula -i imprimirá el tipo sin clasificación (por ejemplo, archivo, directorio); mayúscula: imprimiré la clasificación, similar a lo que cabría esperar en un sistema Linux. Querrá usar mayúsculas -I para que funcione en esa plataforma – verboze

0

Puede usar libmagic que es una versión de biblioteca de la línea de comandos de Unix file.

Hay envoltorio para muchos idiomas:

0

a LIS los nombres de archivo de texto t en dir/subdirectorios actuales:

$ grep -rIl '' 

Binarios:

$ grep -rIL '' 

Para comprobar archivo en particular, modificar ligeramente comando:

$ grep -qI '' FILE 

a continuación, el código de salida registrará '0' significa que el archivo es un texto; '1' - binario. Podría verificar:

$ echo $?

+0

Esta es una solución de trabajo. Por favor, explique el motivo negativo, tal vez debería mejorar la respuesta de alguna manera – bam

+0

Lo probé en archivos generados por dd y por nano. Tu método funciona muy bien. También estoy interesado por qué hubo votos abajo. – Daniel

Cuestiones relacionadas