нехватка памяти для построения массивной строки

#c#

#c#

Вопрос:

У меня есть программа, которая преобразует байт [] в строку шестнадцатеричного:

 byte[] bytes = File.ReadAllBytes(infile);

try
{
    StringBuilder sb = new StringBuilder(BitConverter.ToString(bytes)); // <--exception 
    hexfield.Text = sb.ToString();  
}

catch(Exception e) 
{
    MessageBox.Show(e.ToString()); 
} 
  

В большинстве случаев это работает нормально. Но когда я использую огромный файл, например, видеофайл размером 103 МБ.flv, у него заканчивается память, и он выдает исключение:

 System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.String.CtorCharArrayStartLength(Char[] value, Int32 startIndex, Int32 length)
at System.BitConverter.ToString(Byte[] value, Int32 startIndex, Int32 length)
at System.BitConverter.ToString(Byte[] value)
 at shex.shexx.hexfield_Dragrop(Object sender, DragEventArgs e)** 
  

Комментарии:

1. Что вам нужно делать с прочитанными байтами?

2. Реальный вопрос, конечно, таков: ПОЧЕМУ. Вы не можете с пользой присвоить это значение элементу управления вводом (при условии, что шестнадцатеричное поле равно одному). Вы должны просто обрезать его до полезного объема.

3. @sll с байтами или шестнадцатеричной строкой? В вопросе говорится: "a program that converts a byte[] to a string of hex"

4. Что не так с File.ReadAllText() методом?

5. @ShadowWizard Файл представляет собой двоичные данные, а не текст, поэтому байты в файле не должны интерпретироваться как символы в определенной кодировке, что File.ReadAllText() и было бы сделано.

Ответ №1:

Я бы использовал BinaryReader для чтения файла по частям и добавления каждой части в stringbuilder вместо того, чтобы читать весь файл сразу и преобразовывать его в строку.

Взгляните на эту документацию.

Ответ №2:

Ну, тогда не загружайте BitConverter.ToString такие большие массивы. Делайте это порциями, скажем, по 1 МБ за раз.

Используйте a BinaryReader для примера.

Ответ №3:

BitConverter.ToString Метод сначала создает char массив, затем создает из него строку, поэтому вам потребуется место для строки дважды в памяти.

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

 StringBuilder b = new StringBuilder(bytes.Length * 3 - 1);
int pos = 0;
while (pos < bytes.Length - 1000) {
  b.Append(BitConverter.ToString(bytes, pos, 1000)).Append('-');
  pos  = 1000;
}
b.Append(BitConverter.ToString(bytes, pos));
hexfield.Text = b.ToString();
  

Однако обратите внимание на комментарий sehe о полезности такой огромной строки. На самом деле лучшим решением может быть вообще не создавать всю строку целиком.

Ответ №4:

Рассматривали ли вы, например, потоковую передачу? Это зависит от того, что вы хотите сделать с этой строкой, если вы отправляете ее, что является наиболее вероятным сценарием, когда вы можете отправлять ее небольшими порциями, для чего и предназначена потоковая передача. Некоторые реализации протокола также позволяют создавать патрон и очищать его, поэтому я бы предложил этот путь.

В вашем случае вы можете прочитать только некоторую часть файла, а затем проанализировать ее. Проверка двоичного файла, классов FileStream и потоковой передачи в целом