6
votes

Comment vérifier si le fichier est binaire?

J'ai écrit la méthode suivante pour voir si un fichier particulier contient uniquement des caractères de texte ASCII ou des caractères de contrôle en plus de cela. Pourriez-vous jeter un coup d'œil à ce code, suggérer des améliorations et signaler des supervisions?

La logique est la suivante: "Si les 500 premiers octets d'un fichier contiennent 5 caractères de contrôle ou plus - signalez-le sous forme de fichier binaire" p>

Merci. P>

public boolean isAsciiText(String fileName) throws IOException {

    InputStream in = new FileInputStream(fileName);
    byte[] bytes = new byte[500];

    in.read(bytes, 0, bytes.length);
    int x = 0;
    short bin = 0;

    for (byte thisByte : bytes) {
        char it = (char) thisByte;
        if (!Character.isWhitespace(it) && Character.isISOControl(it)) {

            bin++;
        }
        if (bin >= 5) {
            return false;
        }
        x++;
    }
    in.close();
    return true;
}


0 commentaires

7 Réponses :


3
votes

x ne semble rien faire.

Et si le fichier est inférieur à 500 octets?

Certains fichiers binaires ont une situation où vous pouvez avoir un en-tête pour les premier N octets du fichier qui contient des données utiles pour une application, mais que la bibliothèque est pour ne pas s'en soucier. Vous pouvez facilement avoir plus de 500 octets d'ASCII dans un préambule comme celui-ci suivi de données binaires dans le gigaoctet suivant.

devrait manipuler une exception si le fichier ne peut pas être ouvert ou lu, etc.


0 commentaires

1
votes

La première chose que j'ai remarquée - non liée à votre question actuelle, mais vous devez fermer votre flux d'entrée dans un bloc enfin pour vous assurer que c'est toujours fait. Généralement, cela gère simplement des exceptions, mais dans votre cas, vous ne fermez même pas les flux de fichiers lors du retour false .

Asible à partir de cela, pourquoi la comparaison avec les caractères de contrôle ISO? Ce n'est pas un fichier "binaire", c'est un "fichier contenant 5 caractères de contrôle ou plus". Un meilleur moyen d'aborder la situation à mon avis, serait d'inverser la fonction de chèques - écrire une fonction isasciitext qui affirme que tous les caractères du fichier (ou dans les 500 premiers octets si vous le souhaitez. ) sont dans un ensemble d'octets qui sont bien connus .

théoriquement, seuls vérifier que les premiers centains de centains d'octets d'un fichier pourraient vous mettre en difficulté s'il s'agissait d'un fichier composite de tri (par exemple, du texte avec des images incorporées), mais dans la pratique, je suppose que tous ces fichiers auront des données d'en-tête binaires à le début pour que vous soyez probablement bien.


0 commentaires

0
votes
  1. Vous ignorez ce que LIRE () renvoie, que si les fichiers sont plus courts que 500 octets?
  2. Lorsque vous retournez faux, vous ne fermez pas le fichier.
  3. Lors de la conversion de l'octet en caractères, vous supposez que votre fichier est 7 bits ASCII.

0 commentaires

3
votes

Depuis que vous appelez cette classe "Isasciitext", vous savez exactement ce que vous recherchez. En d'autres termes, ce n'est pas "istexttinclurrentLocaleCodinginging". Ainsi, vous pouvez être plus précis avec: xxx

éditer, une longue date ultérieure - il est souligné dans un commentaire que ce simple contrôle serait trébuché par un texte Fichier qui a commencé avec beaucoup de nouvelles lignes. Il serait probablement préférable d'utiliser une table d'octets "OK" et d'inclure des caractères imprimables (y compris le retour de chariot, la nouvelle ligne et l'onglet, et éventuellement un flux de former si de nombreux documents modernes utilisent ceux-ci), puis vérifiez la table.


2 commentaires

C'est une tragédie que celle-ci est marquée comme la réponse correcte, lorsque cet algorithme classerait un fichier contenant "ceci \ r \ n \ r \ nonly \ r \ ntext" comme binaire.


@Ingo vrai; Il serait préférable de vérifier un rapport de caractères de contrôle aux non-contrôles et de vérifier également des cas spéciaux tels que les caractères de contrôle communs dans le texte. J'étais si jeune quand j'ai tapé dans cette réponse :)



0
votes

Cela ne fonctionnerait pas avec les packages d'installation JDK pour Linux ou Solaris. Ils ont un script de shell, puis une goutte de données BI.

Pourquoi ne pas vérifier le type MIME en utilisant une bibliothèque comme jmimemagic ( http: // http: //sourceforge.net/projects/jmimemagic/ ) et déssidieux basé sur le mimeType Comment gérer le fichier.


0 commentaires

3
votes
  1. échoue mal si la taille du fichier est inférieure à 500 octets

  2. la ligne Char it = (Char) Vérifiez; est conceptuellement douteux, il mélange des octets et des concepts de caractères, c'est-à-dire. suppose implicitement que le codage est un octet = un caractère (eux, il exclut les codages Unicode). En particulier, il échoue si le fichier est codé UTF-16.

  3. Le retour à l'intérieur de la boucle (légèrement mauvaise pratique imo) oublie de fermer le fichier.


0 commentaires

0
votes

On pourrait analyser et comparer AgeInst une liste des octets d'en-tête de fichier binaire connus, tels que celui fourni Ici .

problème est, il faut avoir une liste triée d'en-têtes binaires uniquement et la liste peut ne pas être complète du tout. Par exemple, la lecture et l'analyse de fichiers binaires contenus dans un bloc-cadre équinoxe. Si l'on doit identifier les types de fichiers spécifiques cependant, cela devrait fonctionner. P>

Si vous êtes sous Linux, pour les fichiers existants sur le disque, natif L'exécution de la commande de fichier devrait bien fonctionner: P>

private static boolean isBinaryFileHeader(byte[] headerBytes) {
    return new String(headerBytes).codePoints().filter(Character::isIdentifierIgnorable).count() >= 5;
}

public void printNestedZipContent(String zipPath) {
    try (ZipFile zipFile = new ZipFile(zipPath)) {
        int zipHeaderBytesLen = 500;
        zipFile.entries().asIterator().forEachRemaining( entry -> {
            String entryName = entry.getName();
            if (entry.isDirectory()) {
                System.out.println("FOLDER_NAME: " + entryName);
                return;
            }
            // Get content bytes from ZipFile for ZipEntry 
            try (InputStream zipEntryStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) {
                // read and store header bytes
                byte[] headerBytes = zipEntryStream.readNBytes(zipHeaderBytesLen);
                // Skip entry, if nested binary file
                if (isBinaryFileHeader(headerBytes)) {
                    return;
                }
                // Continue reading zipInputStream bytes, if non-binary
                byte[] zipContentBytes = zipEntryStream.readAllBytes();
                int zipContentBytesLen = zipContentBytes.length;
                // Join already read header bytes and rest of content bytes
                byte[] joinedZipEntryContent = Arrays.copyOf(zipContentBytes, zipContentBytesLen + zipHeaderBytesLen);
                System.arraycopy(headerBytes, 0, joinedZipEntryContent, zipContentBytesLen, zipHeaderBytesLen);
                // Output (default/UTF-8) encoded text file content
                System.out.println(new String(joinedZipEntryContent));
            } catch (IOException e) {
                System.out.println("ERROR getting ZipEntry content: " + entry.getName());
            }
        });
    } catch (IOException e) {
        System.out.println("ERROR opening ZipFile: " + zipPath);
        e.printStackTrace();
    }
}


0 commentaires