Шестнадцатеричный редактор для открытия большого двоичного файла

Я хочу создать шестнадцатеричный редактор для открытия больших двоичных файлов. Это мой код Это хорошо работает для небольших файлов. Но когда я открываю большие файлы, редактор Hex сталкивается с проблемой.

data[] ... array of byte

string str = "";
byte[] temp = null;
int i;
for (i = 0; i < (data.Length - 16); i += 16)
{
    temp = _sub_array(data, i, 16);
    str += BitConverter.ToString(temp).Replace("-", "\t");
    str += "\n";
}

temp = _sub_array(data, i, (data.Length - i));
str += BitConverter.ToString(temp).Replace("-", "\t");

richTextBox.Text = str;

2 ответа

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

  • Если вы загружаете весь файл в byte[], то вы могли бы иметь проблемы с памятью и, возможно, бросить OutOfMemoryException
  • Вы объединяете string несколько раз. Это не только проблема с памятью, но и с производительностью (ссылка на статью Джона Скита http://www.yoda.arachsys.com/csharp/stringbuilder.html).
  • Вы _sub_array() вызывается повторно и возвращает длину 16 byte[]Еще одна проблема с памятью и производительностью.
  • Ты звонишь String.Replace() неоднократно (см. пул 2).

Я считаю, что это проблемы с памятью, потому что мы не знаем, когда сборщик мусора очистит память.

Итак, давайте рассмотрим эти потенциальные проблемы:

  • Читайте файл по 16 байт за раз (комментарий @EZI), это также устраняет необходимость _sub_array(), Посмотрите на класс FileStream, чтобы читать 16 байтов за раз.
  • BitConverter.ToString() эти 16 байтов в StringBuilder с StringBuilder.AppendLine() (Мой комментарий), но не делайте String.Replace() пока вы не закончили читать файл.
  • Как только вы закончите чтение файла, вы можете назначить StringBuilder на ваш RichTextBox так (sb - это имя переменной, используемой для StringBuilder): richTextBox.Text = sb.ToString();

Надеюсь это поможет...

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

data[] ... array of byte

private void button1_Click(object sender, EventArgs e)
{
    Thread t = new Thread(readHexFile);
    t.Start();
}

private void readHexFile()
{
    string str = "";
    byte[] temp = null;
    int i;
    for (i = 0; i < (data.Length - 16); i += 16)
    {
        temp = _sub_array(data, i, 16);
        str += BitConverter.ToString(temp).Replace("-", "\t");
        str += "\n";
    }

    temp = _sub_array(data, i, (data.Length - i));
    str += BitConverter.ToString(temp).Replace("-", "\t");

    BeginInvoke(new Action(()=> richTextBox.Text = str));
}

Вам нужно будет добавить "using System.Threading", чтобы получить доступ к потокам. Также обратите внимание на BeginInvoke с работой richTextBox.Text в лямбда-выражении. Это необходимо, когда вы запускаете обработку данных в отдельном потоке, потому что, если вы попытаетесь получить доступ к текстовому полю непосредственно с этим потоком, Windows будет жаловаться на вызов между потоками. Только поток, который сделал элемент управления, имеет доступ к нему напрямую. BeginInvoke не имеет прямого доступа к элементу управления, поэтому вы можете использовать его из потока обработки данных, чтобы получить текст, записанный в элемент управления. Это остановит обработку данных от "смешения" отзывчивости пользовательского интерфейса.

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

РЕДАКТИРОВАТЬ: я оставил строку из вашего кода, как это было, но я согласен с комментарием, предлагая вместо этого StringBuilder. Строки являются неизменяемыми, поэтому каждый раз, когда вы соединяете строку, внутренне происходит то, что вся строка отбрасывается и создается новая строка с дополнительным текстом. Так что да, также переключитесь на объект StringBuilder.

Другие вопросы по тегам