4

我已经为此苦苦挣扎了一段时间。我创建了一个实用程序,允许您打开 .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);  
                    }
                }
            }
        }
    }
}
4

2 回答 2

4

首先,您不想要 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);
    }
}
于 2014-06-17T17:21:12.687 回答
1

正如 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);  
                }
            }
        }
    }
于 2014-06-17T17:16:36.460 回答