Преобразование байтового массива в строку и обратно в C # - PullRequest
19 голосов
/ 14 сентября 2009

Итак, вот в чем дело: я пытаюсь открыть файл (из байтов), преобразовать его в строку, чтобы я мог связываться с некоторыми метаданными в заголовке, преобразовать их обратно в байты и сохранить. Проблема, с которой я сейчас сталкиваюсь, связана с этим кодом. Когда я сравниваю строку, которая была преобразована взад-вперед (но не изменена иным образом), в исходный байтовый массив, это неравно. Как я могу сделать эту работу?

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;
}

Вот как я их сравниваю.

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

Я уверен, что это UTF-8, используя:

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

, который возвращает «System.Text.UTF8Encoding».

Ответы [ 4 ]

16 голосов
/ 14 сентября 2009

Попробуйте статические функции в классе Encoding, который предоставляет вам экземпляры различных кодировок. Вам не нужно создавать экземпляр Encoding только для преобразования в / из байтового массива. Как вы сравниваете строки в коде?

Редактировать

Вы сравниваете массивы, а не строки. Они неравны, потому что они ссылаются на два разных массива; использование оператора == будет сравнивать только их ссылки, а не их значения. Вам нужно будет проверить каждый элемент массива, чтобы определить, эквивалентны ли они.

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;
}
7 голосов
/ 22 декабря 2011

Если у вас есть необработанные байты (8-битные символы, которые невозможно распечатать) и вы хотите манипулировать ими как строкой .NET и превратить их обратно в байты, вы можете сделать это с помощью

Encoding.GetEncoding(1252)

вместо кодировки UTF8. Эта кодировка позволяет получить любое 8-разрядное значение и преобразовать его в 16-разрядный символ .NET и обратно, не теряя никакой информации.

В конкретном случае, который вы описали выше, с двоичным файлом вы не сможете "связываться с метаданными в заголовке" и работать правильно, если длина данных, с которыми вы связываетесь, не изменяется. Например, если заголовок содержит

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

и вы хотите изменить ABC на DEF, это должно работать так, как вы хотите. Но если вы хотите изменить ABC на WXYZ, вам придется записать поверх байта, следующего за «C», или вы (по сути) переместите все на один байт дальше вправо. В типичном двоичном файле это сильно испортит.

Если байты после «ABC» являются пробелами или нулевыми символами, есть большая вероятность, что запись больших замещающих данных не вызовет проблем - но вы все равно не можете просто заменить ABC на WXYZ в строке .NET, делая его длиннее - вам придется заменить ABC {what_follows_it} на WXYZ. Учитывая это, вы можете обнаружить, что проще оставить данные в виде байтов и записать замещающие данные по одному байту за раз.

5 голосов
/ 14 сентября 2009

Из-за того, что в .NET-строках используются строки Unicode, вы больше не можете делать это, как это делали люди в C. В большинстве случаев вам даже не следует пытаться переходить назад и вперед из строки < -> байтовый массив, если его содержимое на самом деле text .

Я должен прояснить этот момент: В .NET, если данные byte[] не текст , не пытайтесь преобразовать их в string, кроме для специальной кодировки Base64 для двоичных данных по текстовому каналу. Это широко распространенное недоразумение среди людей, работающих в .NET.

3 голосов
/ 14 сентября 2009

Ваша проблема заключается в том, что вы сравниваете массив байтов:

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

Это всегда будет возвращать false, поскольку вы сравниваете адрес байтового массива, а не значения, которые он содержит. Сравните строковые данные или используйте метод сравнения байтовых массивов. Вы также можете сделать это вместо этого:

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