51 votes

Comment puis-je déterminer si un fichier est binaire ou texte en c#?

Je dois déterminer à 80% si un fichier est binaire ou texte, y a-t-il un moyen de le faire même rapidement et salement en c#?

31voto

zvolkov Points 9673

Il existe une méthode appelée chaînes de Markov. Analysez quelques fichiers de modèle des deux types et pour chaque valeur d'octet de 0 à 255, recueillez des statistiques (essentiellement des probabilités) d'une valeur ultérieure. Cela vous donnera un profil de 64 Ko (256x256) que vous pouvez comparer avec vos fichiers d'exécution (dans une fourchette de %).

Apparemment, c'est ainsi que fonctionne la fonction Auto-Détection de l'encodage des navigateurs.

21voto

Ron Warholic Points 7479

Je chercherais probablement une abondance de caractères de contrôle qui seraient généralement présents dans un fichier binaire mais rarement dans un fichier texte. Les fichiers binaires ont tendance à utiliser suffisamment de 0 que simplement tester de nombreux octets à 0 serait probablement suffisant pour attraper la plupart des fichiers. Si vous vous souciez de la localisation, vous devriez également tester des motifs multioctets.

Cela dit, vous pouvez toujours être malchanceux et obtenir un fichier binaire qui ressemble à du texte ou vice versa.

10voto

Si la vraie question ici est "ce fichier peut-il être lu et écrit en utilisant StreamReader/StreamWriter sans modification?", alors la réponse est ici:

/// 
/// Détecter si un fichier est du texte et détecter l'encodage.
/// 
/// 
/// L'encodage détecté.
/// 
/// 
/// Le nom du fichier.
/// 
/// 
/// Le nombre de caractères à utiliser pour les tests.
/// 
/// 
/// vrai si le fichier est du texte.
/// 
public static bool IsText(out Encoding encoding, string fileName, int windowSize)
{
    using (var fileStream = File.OpenRead(fileName))
    {
    var rawData = new byte[windowSize];
    var text = new char[windowSize];
    var isText = true;

    // Lire les octets bruts
    var rawLength = fileStream.Read(rawData, 0, rawData.Length);
    fileStream.Seek(0, SeekOrigin.Begin);

    // Détecter correctement l'encodage (à partir du blog de Rick Strahl)
    // http://www.west-wind.com/weblog/posts/2007/Nov/28/Detecting-Text-Encoding-for-StreamReader
    if (rawData[0] == 0xef && rawData[1] == 0xbb && rawData[2] == 0xbf)
    {
        encoding = Encoding.UTF8;
    }
    else if (rawData[0] == 0xfe && rawData[1] == 0xff)
    {
        encoding = Encoding.Unicode;
    }
    else if (rawData[0] == 0 && rawData[1] == 0 && rawData[2] == 0xfe && rawData[3] == 0xff)
    {
        encoding = Encoding.UTF32;
    }
    else if (rawData[0] == 0x2b && rawData[1] == 0x2f && rawData[2] == 0x76)
    {
        encoding = Encoding.UTF7;
    }
    else
    {
        encoding = Encoding.Default;
    }

    // Lire le texte et détecter l'encodage
    using (var streamReader = new StreamReader(fileStream))
    {
        streamReader.Read(text, 0, text.Length);
    }

    using (var memoryStream = new MemoryStream())
    {
        using (var streamWriter = new StreamWriter(memoryStream, encoding))
        {
        // Écrire le texte dans un tampon
        streamWriter.Write(text);
        streamWriter.Flush();

        // Obtenir le tampon de la mémoire pour la comparaison
        var memoryBuffer = memoryStream.GetBuffer();

        // Comparer uniquement les octets lus
        for (var i = 0; i < rawLength && isText; i++)
        {
            isText = rawData[i] == memoryBuffer[i];
        }
        }
    }

    return isText;
    }
}

4voto

Jeff Yates Points 36725

Rapide et simple consiste à utiliser l'extension de fichier et à rechercher des extensions de texte courantes telles que .txt. Pour cela, vous pouvez utiliser l'appel Path.GetExtension. Tout autre chose ne serait pas vraiment classée comme "rapide", même si cela pourrait bien être sale.

2voto

Chad Ruppert Points 3073

Une manière vraiment vraiment vraiment sale serait de construire une regex qui ne prend que du texte standard, de la ponctuation, des symboles et des caractères d'espacement, charger une partie du fichier dans un flux de texte, puis l'exécuter contre la regex. Selon ce qui qualifie un fichier de texte pur dans votre domaine de problème, aucun match réussi indiquerait un fichier binaire.

Pour prendre en compte l'unicode, assurez-vous de marquer l'encodage sur votre flux en conséquence.

C'est vraiment sous-optimal, mais vous avez dit rapide et sale.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X