【问题标题】:Hex editor for open large binary file用于打开大型二进制文件的十六进制编辑器
【发布时间】:2015-10-26 02:31:30
【问题描述】:

我想创建一个十六进制编辑器来打开大型二进制文件。 这是我的代码。它适用于小文件。但是当我打开大文件时,十六进制编辑器会遇到问题。

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;

【问题讨论】:

  • 不要将整个文件加载到内存中。在需要时加载必要的部件。
  • 考虑使用 StringBuilder 而不是字符串。
  • "十六进制编辑器面临问题" => 问题已通过 solution 解决。

标签: c# hex-editors


【解决方案1】:

因此,您已经获得了用于小文件的工作代码,但您面临处理大文件的问题。你没有提到这些问题是什么,所以这里有一些猜测:

  • 如果您将整个文件加载到byte[],那么您可能会遇到内存问题并可能会抛出OutOfMemoryException
  • 您重复连接string。这不仅是内存问题,也是性能问题(参考 Jon Skeet 的文章http://www.yoda.arachsys.com/csharp/stringbuilder.html
  • You're _sub_array() 被重复调用并返回一个长度为 16 的 byte[],这又是一个内存和性能问题。
  • 您反复拨打String.Replace()(参见第2 条)。

我认为这些是内存问题,因为我们不知道垃圾收集器何时会清理内存。

让我们来解决这些潜在的问题:

  • 一次读取 16 个字节的文件(@EZI 注释),这也消除了对您的_sub_array() 的需要。查看 FileStream 类,一次读取 16 个字节。
  • BitConverter.ToString() 将这 16 个字节与 StringBuilder.AppendLine() 合并为 StringBuilder(我的评论),但在阅读完文件之前不要执行 String.Replace()
  • 读完文件后,您可以像这样将StringBuilder 分配给RichTextBox(sb 是用于StringBuilder 的变量名):richTextBox.Text = sb.ToString();

希望这会有所帮助...

【讨论】:

    【解决方案2】:

    正如 cmets 中所说,您应该尽量避免一次读取整个文件。但是,如果您一次需要整个文件在内存中,我认为您的主要问题可能是程序在读取和转换数据时会遇到的“粘性”。您更明智地使用单独的线程进行十六进制工作,并让主线程专注于保持您的 UI 顺利运行。无论哪种方式,您也可以使用任务而不是线程。所以使用你的代码 sn-p,让它看起来更像这样:

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

    您需要添加“使用 System.Threading”才能访问线程。还要注意 BeginInvoke 与 richTextBox.Text 在 lambda 表达式中的工作。当您在单独的线程上运行数据处理时,这是必要的,因为如果您尝试使用该线程直接访问文本框,Windows 将抱怨跨线程调用。只有创建控件的线程才被允许直接访问它。 BeginInvoke 不直接访问控件,因此您可以从数据处理线程中使用它来获取写入控件的文本。这将阻止数据处理“破坏” UI 响应能力。

    如果您从未这样做过,这可能会令人生畏,但请相信我。如果你掌握了线程和任务的窍门(它们在机器内部是不同的,但可以由类似的开发人员工具操作),你就再也不想从主线程渲染到 UI。

    编辑:我保留了您代码中的字符串,但我同意建议使用 StringBuilder 的评论。字符串是不可变的,因此每次连接到字符串时,在内部发生的情况是整个字符串都被废弃,并且正在使用附加文本创建一个新字符串。所以,是的,也要切换到 StringBuilder 对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-01
      • 2011-03-14
      • 2015-04-13
      • 2014-01-22
      • 1970-01-01
      • 2014-10-30
      • 2012-05-10
      • 2012-02-14
      相关资源
      最近更新 更多