【问题标题】:Can't see past the NULL Terminator看不到 NULL 终止符
【发布时间】:2014-06-17 16:13:17
【问题描述】:

我已经为此苦苦挣扎了一段时间。我创建了一个实用程序,允许您打开 .TXT 文件。这些文本文件包含 PCL(打印命令语言)。当我导入一个新文件时,它被 \0(NULL 终止符)截断。因为 PCL 文件在我导入的所有内容中随机包含图形图像,所以在第一个位图图像处被截断,因为位图图像以 NULL 开头。

这是此处看到的确切问题:Displaying Raw Data From Image File Using TextBox or RichTextBox?

很遗憾,由于我的(新手)声誉低(需要 15 个代表),我无法对这个帖子发表评论。也无法粘贴屏幕截图(需要 10 个代表)。


Notepad++ 显示信息的方式如下:


这是我的 RichTextBox 显示相同信息的方式:


这是一个问题的原因(缩小):

栅格数据正好在我需要的两部分数据(PCL)之间。栅格数据下方的所有信息都不会被拉入。


这是我尝试过的(注意:我使用的是自定义 RichTextBox,但这不会影响任何事情,因为它只是一个具有拖放功能的 RichTextBox):

byte[] bytes = new byte[2048];
string data = System.Text.Encoding.ASCII.GetString(bytes);
dragDropRichTextBox1.Text = data.Replace("\0", @"1");

这只会导致 2048 个数字“1”字符链,而没有任何文本文件的数据被拉入。非常感谢任何帮助。

无论我做什么,我都想保留我当前的拖放功能:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PCL_Utility
{
    public class DragDropRichTextBox : RichTextBox
    {
        public DragDropRichTextBox()
        {
            this.AllowDrop = true;
            this.DragDrop += DragDropRichTextBox_DragDrop;
        }

        void DragDropRichTextBox_DragDrop(object sender, DragEventArgs e)
        {
            //string[] fileText = e.Data.GetData(DataFormats.FileDrop) as string[];
            string[] fileText = e.Data.GetData(DataFormats.FileDrop) as string[];

            if (fileText != null)
            {
                foreach (string name in fileText)
                {
                    try
                    {
                        this.AppendText(File.ReadAllText(name) + "\n -------- End of File -------- \n\n");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);  
                    }
                }
            }
        }
    }
}

【问题讨论】:

  • 我不确定答案,但是有没有办法可以读取文件的大小然后读取那么多字节?
  • 我明白你在说什么。不管出于何种原因,即使我为每个字符都有足够的字节数,它也会使“每个”字符成为 1,而不仅仅是“\0”字符。我所知道的是,如果我再提高 4 点声望点,我就会丢下这头野兽的一些截图!
  • 请用您正在编程的语言标记您的问题。
  • 标签已更新。
  • RichTextBox 旨在显示文本,而不是二进制数据。特别是富文本。除了它显示的乱码之外,它将 PCL 数据中的二进制零视为字符串终止符。您必须将数据转换为适合 RTB 和人类的格式。十六进制很常见。使用 BitConverter.ToString(byte[]) 很简单。

标签: c# null .net-4.5 terminator


【解决方案1】:

首先,您不需要 ASCII 编码。 ASCII 是 7 位编码。读取的任何设置了高位的字符(即字符代码 128 到 255)都会被解码器转换为问号。因此,将二进制数据读取为 ASCII 会破坏您的数据。

其次,富文本框在后台使用 Windows 控件,该控件旨在处理以空字符结尾的字符串。所以它会在第一次看到'\0' 字符时截断文本。如果要在编辑控件中显示二进制数据,则需要修改要显示的文本。

您的“文本”文件实际上不是文本,因为它们包含二进制(即非人类可读)数据。最好的办法是打开文件并将整个内容作为二进制文件读入内存缓冲区。那就是:

byte[] fileBytes = File.ReadAllBytes("filename");

然后,如果要在文本控件中显示数据,则必须创建一个表示数据的字符串。我会建议类似:

StringBuilder sb = new StringBuilder();
foreach (var b in fileBytes)
{
    // handle printable characters
    if (b >= 32 || b == 10 || b == 13 || b = 9) // lf, cr, tab
        sb.Append((char)b);
    else
    {
        // handle control characters
        switch (b)
        {
            case 0 : sb.Append("(nul)"); break;
            case 27 : sb.Append("(esc)"); break;
            // etc.
        }
    }
}

您可能想要构建一个查找表,其中包含要转换的每个值的字符串,而不是构建一个大的 switch 语句。字典可能是最好的。比如:

private Dictionary<byte, string> Conversions = new Dictionary<byte, string>()
{
    {0, "(nul)"},
    {27, "(esc)"},
    // etc.
};

那么你的循环可以这样做:

foreach (var b in fileBytes)
{
    string s;
    if (Conversions.TryGetValue(b, out s))
    {
        sb.Append(s);
    }
    else
    {
        sb.Append((char)b);
    }
}

【讨论】:

  • 感谢吉姆。这是非常有用的信息。我会尽快解决这个问题,并告诉你我发现了什么。
【解决方案2】:

而不是试图将文件数据读入字符串,正如 Jim Mischel 回答的那样,应该将其读入字节数组并进行处理。

这是一个静态类,它将文件读入字节数组,并根据字典查找对其进行处理。对于不可打印的 ASCII 字符和超过 127 的所有值,我已经在字典中预先填充了“\00”。

    public static class BinaryFile
    {

        private static string[] __byteLookup = new string[256];

        static BinaryFile()
        {
            // Display printable ASCII characters as-is
            for (int i = 0x20; i < 0x7F; i++) { __byteLookup[i] = ((char)i).ToString(); }

            // Display non-printable ASCII characters as \{byte value}
            for (int i = 0; i < 0x20; i++) { __byteLookup[i] = "\\" + i.ToString();}
            for (int i = 0x7F; i <= 0xFF; i++) { __byteLookup[i] = "\\" + i.ToString(); }

            // Replace pre-populated values with custom values here if desired.
        }

        public static string ReadString(string filename)
        {
            byte[] fileBytes = System.IO.File.ReadAllBytes(filename);

            return String.Join("", (from i in fileBytes select __byteLookup[i]).ToArray());
        }
    }

编辑因为您想将此与您的自定义拖放代码一起使用,所以用法应该是:

   void DragDropRichTextBox_DragDrop(object sender, DragEventArgs e)
    {
        string[] fileText = e.Data.GetData(DataFormats.FileDrop) as string[];

        if (fileText != null)
        {
            foreach (string name in fileText)
            {
                try
                {
                    // Read each file using the helper class rather than File.ReadAllText
                    // then append the end-of-file line
                    this.AppendText(BinaryFile.ReadString("your_file_name.txt") 
                        + "\n -------- End of File -------- \n\n");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);  
                }
            }
        }
    }

【讨论】:

  • 如果文件中包含代码高于 127 的字符,它将不起作用。ASCII 是 7 位编码。它会将 127 以上的任何字符转换为问号。
  • 你是对的。我已经修改了我的答案,以免误导任何人。
  • 看起来这样做我必须摆脱我当前的拖放功能。我一直试图调和你在这里给我的东西和我所拥有的东西,但我不能让两者一起工作。我已经更新了我的原始帖子,以显示我创建的拖放富文本框,如果您想查看的话。我不是最先进的程序员。如果你愿意的话,这是我离家最远的地方。任何帮助表示赞赏,但当然不是必需的。感谢您迄今为止的帮助。
  • @user3290333 看起来您正在尝试显示拖到 RichTextBox 的所有文件,并由文件结束标记分隔。这应该是可行的:用辅助函数替换你的 File.ReadAllText (见编辑)。我还没有测试过,但它应该可以工作。
  • 数组比字典更高效:private static readonly string[] __byteLookup = new string[256];。另外,您可以使用 int 对其进行索引并避免字节转换。
猜你喜欢
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
  • 2017-04-16
相关资源
最近更新 更多