Подтвердить что ты не робот

Преобразование байтового массива в строку и обратно в С#

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

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".

4b9b3361

Ответ 1

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

Edit

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

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

Ответ 2

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

Encoding.GetEncoding(1252)

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

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

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

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

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

Ответ 3

В связи с тем, что строки .NET используют строки Unicode, вы больше не можете делать это, как это делали люди на C. В большинстве случаев вам не следует даже пытаться перемещаться из массива string ↔ byte, если только содержимое на самом деле является текстом.

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

Ответ 4

Ваша проблема будет выглядеть так, как вы сравниваете массив байтов:

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

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

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