在数字时代,经常需要处理各种类型的文件,其中一些文件是二进制格式的。这些文件可能包含图像、音频、视频或者程序代码等数据。对于开发者和技术人员来说,能够查看和编辑这些二进制文件是非常重要的。本文将介绍一个简单的Windows Forms应用程序,它不仅可以打开二进制文件并清晰地显示其内容,还可以对这些文件进行编辑。这个应用程序最初是为了能够简单地打开和查看二进制文件而设计的,它的设计限制是只读取最多10KB大小的文件,因为更大的文件处理并不是它的设计初衷。
这个应用程序的灵感来源于作者五年前写的一篇关于多进制数字编辑组件的文章。当时,作者需要打开和读取一个二进制文件,但找不到一个简单且免费的能够做到这一点的工具。作者还希望查看每个字节的地址,并且如果能够以不同的视图打开和检查文件,为什么不允许编辑它呢?于是,作者决定利用自己的多进制数字编辑器,将其整合进这个应用程序中。
这个项目最初是使用Visual Studio 2010 Express、Windows Forms和.NETFramework 3.5开发的,现在作者已经将其更新到使用Visual Studio 2015 Community和.NET Framework 4.0。尽管现在市面上已经有了其他一些工具可以做到这一点,比如HexEdit,它是一个功能更全面的工具,但作者仍然决定分享这个项目,因为它简单易用,并且作者希望它能够成为一个有用的工具,比如用于旧游戏模拟器ROM文件的文本查找和翻译。
应用程序的核心功能是将字节列表以数字形式(十进制、十六进制、二进制或八进制)显示出来。要做到这一点,首先需要打开一个文件。任何类型的文件都可以,无论是图像文件还是文本文件。下面的代码片段展示了如何打开文件,并将文件内容存储在名为bytes的数组变量中,然后调用displayBytes()方法。每当需要在文本框中渲染二进制数据时,都会调用displayBytes()方法。
if (dialogResult == DialogResult.OK) {
if (File.Exists(openFileDialog1.FileName)) {
fileStream = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
// Limits the size of files this application can open and display.
if (fileStream.Length < 10000) {
bytes = ReadFully(fileStream);
displayBytes();
} else {
txtBinary.Text = "文件过大";
}
}
}
使用一些数学和逻辑运算,将二进制数据呈现在文本框中。用户可以设置一些选项,例如:以十六进制显示字节、显示提示、使用换行符、尝试转换为ASCII字符、当鼠标移动时显示信息以及当鼠标移动时自动选择。下面的代码完成了所有的渲染工作。
private void displayBytes() {
char validChar;
int padlef = cbHexadecimal.Checked ? 2 : 3;
txtBinary.Clear();
if (bytes == null)
return;
StringBuilder text = new StringBuilder();
for (int i = 0; i < bytes.Length; i++) {
if (UseBytesPerLine && i != 0 && (i % options.BytesPerLine == 0))
text.AppendLine();
if (options.ConvertCharacter)
if (tryGetChar(bytes[i], out validChar)) {
text.Append(validChar.ToString().PadLeft(padlef));
text.Append("\n");
continue;
}
if (cbHexadecimal.Checked) {
text.Append(bytes[i].ToString("X").PadLeft(2, '0'));
} else
text.Append(bytes[i].ToString().PadLeft(3, ' '));
text.Append("\n");
}
txtBinary.Text = text.ToString();
updateAddress();
}
之后,调用updateAddress()方法来填充每行的第一个字节地址位置。所有这些都是基于用户设置的选项来计算的。下面的代码展示了如何做到这一点。
private void updateAddress() {
txtAddress.Clear();
int height;
height = 0;
int charIndex = txtBinary.GetCharIndexFromPosition(new Point(0, height));
int charIndexFromLastLine = txtBinary.GetCharIndexFromPosition(new Point(0, txtBinary.Height - 2));
int lastLine = txtBinary.GetLineFromCharIndex(charIndexFromLastLine);
int breaklineCount = Environment.NewLine.Length;
StringBuilder addresses = new StringBuilder();
for (int i = 0; i < lastLine - 1; i++) {
height = txtBinary.Font.Height * i + 1;
charIndex = txtBinary.GetCharIndexFromPosition(new Point(1, height));
if (options.UseBreakLine)
charIndex -= breaklineCount * i;
// Do not count the breakline characters
int calculatedByteIndex = -1;
if (options.DisplayHexadecimal) {
// When displaying hexadecimal every byte occupy up to 2 characters 0 - FF.
// Between every byte there is a space. Based on this information,
// the index on the byte array for the char index from the text area will be:
calculatedByteIndex = charIndex / 3;
} else {
calculatedByteIndex = charIndex / 4;
}
addresses.AppendLine((calculatedByteIndex).ToString("X"));
}
// for
txtAddress.Text = addresses.ToString();
}
GetCharIndexFromPosition方法用于获取给定屏幕相对位置的当前字符位置。注意GetCharIndexFromPosition方法将换行符视为字符,因此charIndex值需要调整。文本框的字体高度用于定义每行的高度。地址只计算可见文本的地址。如果Inspector以十六进制值显示,则考虑每个字节使用3个字符,否则使用4个字符。然后可以计算字节,如果得到每行的第一个字节的位置(charIndex)并将其除以3或4,取决于它是否显示十进制或十六进制值,可以得到每行的地址。
除此之外,作者还使用了一些资源来增加功能,以改善GUI。在这里详细讨论所有这些功能可能会过于繁琐。作者只会在下面指出它们。如果是学生,并且正在尝试学习如何实现其中任何一项,请查看源代码,看看它是如何实现的。如果有任何疑问,欢迎联系作者。
作者添加了model.Options来使用用户控件的DataBindings。这些选项定义了应用程序的行为和数据呈现方式。用户可以在名为OptionsView的表单中更改这些选项。这些选项被加载并存储在位于Application.LocalUserAppDataPath特殊文件夹的用户设置文件中。
为大多数GUI组件添加了工具提示,用户可以打开或关闭它们。有一个选项可以在鼠标指针悬停在字节上时,在StatusStrip中显示当前字节的信息。双击字节位置会显示EditByte表单,该表单使用多进制数字编辑器组件,允许用户更改选定的字节。
使用Doxygen工具生成了文档。
升级到.NETFramework 4.6.1
添加用户帮助工具(问号)
使用资源文件添加多语言支持
为Web应用程序创建类似的控件