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#?
Réponses
Trop de publicités?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.
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.
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;
}
}
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.
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.