web-dev-qa-db-fra.com

Conversion d'un tableau d'octets en chaîne et inversement en C #

Voici donc l'affaire: j'essaie d'ouvrir un fichier (à partir d'octets), de le convertir en chaîne afin de pouvoir jouer avec des métadonnées dans l'en-tête, le reconvertir en octets et l'enregistrer. Le problème que je rencontre en ce moment est avec ce code. Lorsque je compare la chaîne qui a été convertie d'avant en arrière (mais non autrement modifiée) au tableau d'octets d'origine, elle est inégale. Comment puis-je faire fonctionner cela?

public static byte[] StringToByteArray(string str)
{
    UTF8Encoding encoding = new UTF8Encoding();
    return encoding.GetBytes(str);
}

public string ByteArrayToString(byte[] input)
{
    UTF8Encoding enc = new UTF8Encoding();
    string str = enc.GetString(input);
    return str;
}

Voici comment je les compare.

byte[] fileData = GetBinaryData(filesindir[0], Convert.ToInt32(fi.Length));
string fileDataString = ByteArrayToString(fileData);
byte[] recapturedBytes = StringToByteArray(fileDataString);
Response.Write((fileData == recapturedBytes));

Je suis sûr que c'est UTF-8, en utilisant:

StreamReader sr = new StreamReader(filesindir[0]);
Response.Write(sr.CurrentEncoding);

qui renvoie "System.Text.UTF8Encoding".

20
Brian Hicks

Essayez les fonctions statiques de la classe Encoding qui vous fournit des instances des différents encodages. Vous ne devriez pas avoir besoin d'instancier le Encoding juste pour convertir vers/à partir d'un tableau d'octets. Comment comparez-vous les chaînes dans le code?

Modifier

Vous comparez des tableaux, pas des chaînes. Ils sont inégaux car ils se réfèrent à deux tableaux différents; en utilisant le == L'opérateur ne comparera que leurs références, pas leurs valeurs. Vous devrez inspecter chaque élément du tableau afin de déterminer s'ils sont équivalents.

public bool CompareByteArrays(byte[] lValue, byte[] rValue)
{
    if(lValue == rValue) return true; // referentially equal
    if(lValue == null || rValue == null) return false; // one is null, the other is not
    if(lValue.Length != rValue.Length) return false; // different lengths

    for(int i = 0; i < lValue.Length; i++)
    {
        if(lValue[i] != rValue[i]) return false;
    }

    return true;
}
16
Adam Robinson

Lorsque vous avez des octets bruts (caractères 8 bits éventuellement non imprimables) et que vous souhaitez les manipuler en tant que chaîne .NET et les reconvertir en octets, vous pouvez le faire en utilisant

Encoding.GetEncoding(1252)

au lieu de UTF8Encoding. Cet encodage fonctionne pour prendre n'importe quelle valeur 8 bits et la convertir en un caractère .NET 16 bits, et inversement, sans perdre aucune information.

Dans le cas spécifique que vous décrivez ci-dessus, avec un fichier binaire, vous ne pourrez pas "jouer avec les métadonnées dans l'en-tête" et faire fonctionner les choses correctement à moins que la longueur des données avec lesquelles vous jouez soit inchangée. Par exemple, si l'en-tête contient

{any}{any}ABC{any}{any}

et vous voulez changer ABC en DEF, cela devrait fonctionner comme vous le souhaitez. Mais si vous voulez changer ABC en WXYZ, vous devrez écrire sur l'octet qui suit "C" ou vous allez (essentiellement) déplacer tout un octet plus loin vers la droite. Dans un fichier binaire typique, cela gâchera énormément les choses.

Si les octets après "ABC" sont des espaces ou des caractères nuls, il y a de meilleures chances que l'écriture de données de remplacement plus importantes ne cause pas de problème - mais vous ne pouvez toujours pas simplement remplacer ABC par WXYZ dans la chaîne .NET, ce qui le rend plus long - vous le feriez doivent remplacer ABC {any_follows_it} par WXYZ. Cela étant, vous constaterez peut-être qu'il est plus facile de laisser les données sous forme d'octets et d'écrire les données de remplacement un octet à la fois.

7
J.Merrill

En raison du fait que les chaînes .NET utilisent des chaînes Unicode, vous ne pouvez plus le faire comme les gens l'ont fait en C. Dans la plupart des cas, vous ne devriez même pas essayer pour aller et venir à partir de la chaîne < -> tableau d'octets à moins que le contenu ne soit réellement texte.

Je dois préciser ce point: Dans .NET, si le byte[] les données ne sont pas texte, alors n'essayez pas de les convertir en string à l'exception du codage spécial Base64 pour les données binaires sur un texte canal. Il s'agit d'un malentendu largement répandu parmi les personnes qui travaillent dans .NET.

5
Sam Harwell

Votre problème semble être la façon dont vous comparez le tableau d'octets:

Response.Write((fileData == recapturedBytes));

Cela retournera toujours false puisque vous comparez l'adresse du tableau d'octets, pas les valeurs qu'il contient. Comparez les données de chaîne ou utilisez une méthode de comparaison des tableaux d'octets. Vous pouvez également le faire à la place:

Response.Write(Convert.ToBase64String(fileData) == Convert.ToBase64String(recapturedBytes));
3
csharptest.net