2009-03-07 11 views

Respuesta

16

No hay ninguna forma garantizada, pero aquí hay un par de posibilidades:

1) Busque un encabezado en el archivo. Desafortunadamente, los encabezados son específicos del archivo, por lo que si bien es posible que pueda descubrir que se trata de un archivo RAR, no obtendrá la respuesta más genérica de si se trata de texto o binario.

2) Cuente el número de caracteres frente a los tipos que no son de carácter. Los archivos de texto serán en su mayoría caracteres alfabéticos, mientras que los archivos binarios, especialmente los comprimidos, como rar, zip, y tal, tenderán a tener bytes más representados.

3) Busque un patrón de líneas nuevas que se repita regularmente.

1

Puede probar la herramienta DROID.

3

Si el archivo consiste en el 0x09 (pestaña) bytes, 0x0A (salto de línea), 0x0C (avance de página), 0x0D (retorno de carro), o 0x20 través 0x7E, entonces es probable que el texto ASCII .

Si el archivo contiene cualquier otro caracter de control ASCII, 0x00 a 0x1F excluyendo los tres anteriores, entonces probablemente sean datos binarios.

El texto UTF-8 sigue un patrón muy específico para cualquier byte con el bit de orden alto, pero las codificaciones de longitud fija como ISO-8859-1 no lo hacen. UTF-16 puede contener con frecuencia el byte nulo (0x00), pero solo en cualquier otra posición.

Necesitaría una heurística más débil para cualquier otra cosa.

9

Eche un vistazo a la biblioteca JMimeMagic.

jMimeMagic es una biblioteca Java para determinar el tipo MIME de archivos o corrientes.

+0

Biblioteca interesante, pero ¿cómo va a ayudar eso? Te dice el tipo de mimo, pero no si es binario o de texto. – Adam

+0

@ Adam ¿No entiendo tu pregunta? Puede deducir del tipo MIME si el archivo es binario o no, ¿verdad? Es decir. si el tipo es 'text/plain' debe ser un archivo de texto. – dhiller

+0

Bien, estaba siendo franco. Lo que quise decir es que todavía tiene que escribir lógica extra para interpretar el tipo mime como binario o como texto. 'text/plain' no es el único tipo de mime basado en texto. – Adam

3

Solo para decirte, he elegido una ruta bastante diferente. En mi caso, solo hay 2 tipos de archivos, las posibilidades de que un archivo dado sea uno binario son altas. Así

  1. presumir que el archivo es binario, trata de hacer lo que se supone que debe hacerse (por ejemplo deserializar)
  2. captura excepción
  3. archivo de tratar como textual
  4. si eso no funciona, algo está mal con el archivo en sí
+0

Creo que este es el mejor enfoque. ¿Realmente te importa cuál es el tipo de archivo? ¿O te importa si puedes hacer ciertas cosas con él? En muchos casos, si puede hacer esas cosas, no necesita saber realmente de qué tipo es. – stackexchanger

10

Ejecute file -bi {filename}. Si lo que devuelve comienza con 'text /', entonces no es binario, de lo contrario lo es. ;-)

+1

Parece que hay "aplicación/javascript" y "aplicación/xml" también. Mirar aquí http://en.wikipedia.org/wiki/Internet_media_type sugiere que no es tan simple. – Aaron

+1

Puede verificar con 'file -i {filename}' y comprobar que NO HAY 'charset = binary'. –

+0

Tengo que decir que no estaba hablando en serio cuando respondí lo anterior. Los archivos de texto son solo archivos binarios interpretados de una manera particular. Si quisiste decir si algo es US-ASCII, entonces podrías verificar cada byte y ver si se ajusta a tu definición de texto. Pero tal vez quisiste decir * cualquier * tipo de codificación de caracteres. Eso va a ser mucho más difícil. Especialmente si se tienen en cuenta los que están usando una codificación basada en entropía (los caracteres que a menudo requieren menos bits). Por otro lado, si se refería a todo US-ASCII, ¿una imagen codificada en Base64 también sería texto? –

5

que utiliza este código y funciona para textos en Inglés y alemán bastante bien:

private boolean isTextFile(String filePath) throws Exception { 
    File f = new File(filePath); 
    if(!f.exists()) 
     return false; 
    FileInputStream in = new FileInputStream(f); 
    int size = in.available(); 
    if(size > 1000) 
     size = 1000; 
    byte[] data = new byte[size]; 
    in.read(data); 
    in.close(); 
    String s = new String(data, "ISO-8859-1"); 
    String s2 = s.replaceAll(
      "[a-zA-Z0-9ßöäü\\.\\*!\"§\\$\\%&/()=\\[email protected]~'#:,;\\"+ 
      "+><\\|\\[\\]\\{\\}\\^°²³\\\\ \\n\\r\\t_\\-`´âêîô"+ 
      "ÂÊÔÎáéíóàèìòÁÉÍÓÀÈÌÒ©‰¢£¥€±¿»«¼½¾™ª]", ""); 
    // will delete all text signs 

    double d = (double)(s.length() - s2.length())/(double)(s.length()); 
    // percentage of text signs in the text 
    return d > 0.95; 
} 
+2

La idea es interesante, pero en lugar de replaceAll, que innecesariamente crea una nueva cadena, simplemente usaría un bucle for para contar texto versus caracteres que no sean de texto. Poner el límite en 1000 caracteres significa que no será * demasiado * costoso de todos modos, pero sigue siendo un costo inútil – miniBill

8

yo hicimos éste. Un poco más simple, pero para los idiomas latinos, debería funcionar bien, con el ajuste de proporción.

/** 
* Guess whether given file is binary. Just checks for anything under 0x09. 
*/ 
public static boolean isBinaryFile(File f) throws FileNotFoundException, IOException { 
    FileInputStream in = new FileInputStream(f); 
    int size = in.available(); 
    if(size > 1024) size = 1024; 
    byte[] data = new byte[size]; 
    in.read(data); 
    in.close(); 

    int ascii = 0; 
    int other = 0; 

    for(int i = 0; i < data.length; i++) { 
     byte b = data[i]; 
     if(b < 0x09) return true; 

     if(b == 0x09 || b == 0x0A || b == 0x0C || b == 0x0D) ascii++; 
     else if(b >= 0x20 && b <= 0x7E) ascii++; 
     else other++; 
    } 

    if(other == 0) return false; 

    return 100 * other/(ascii + other) > 95; 
} 
+1

Gracias por esta función. Una cosa que tengo problemas para averiguar es qué está pasando con el valor de retorno: 'return (ascii + otro) * 100/otro> 95;' Que, a menos que me falta algo, siempre será verdadero: En su mayoría, el tamaño será '1024', al igual que' data.length' y por lo tanto '(ascii + otro)'. Así que si '(ascii + otro) * 100 == 102400' entonces' 102400/otro> 95' => '102400> 95 * otro' =>' otro <1078' Lo que significa que debe haber más de 1078 (de 1024) "otros" para que esto sea falso, obviamente imposible. ¿Quizás quiso decir ?: '(otro/tamaño * 100> 95)' ¿O me está faltando algo? – Inversus

+0

Creo que tienes razón. Solucionado el código. –

+0

Cool cool. Ya, terminé yendo con eso también. Gracias de nuevo :) – Inversus

5

Usando http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType(java.nio.file.Path)

boolean isBinaryFile(File f) throws IOException { 
     String type = Files.probeContentType(f.toPath()); 
     if (type == null) { 
      //type couldn't be determined, assume binary 
      return true; 
     } else if (type.startsWith("text")) { 
      return false; 
     } else { 
      //type isn't text 
      return true; 
     } 
    } 
+3

Eso solo comprueba la extensión del archivo y no el contenido del archivo y, por lo tanto, no sirve. – ares

+1

Eso depende de lo que esté instalado, de acuerdo con los documentos. – Adam

Cuestiones relacionadas