Шестнадцатеричный редактор для открытия большого двоичного файла
Я хочу создать шестнадцатеричный редактор для открытия больших двоичных файлов. Это мой код Это хорошо работает для небольших файлов. Но когда я открываю большие файлы, редактор 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()
вызывается повторно и возвращает длину 16byte[]
Еще одна проблема с памятью и производительностью. - Ты звонишь
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.