Can't see past the NULL Terminator

痞子三分冷 提交于 2019-12-13 13:34:04

问题


I've been struggling with this for a while. I created a utility that allows you to open .TXT files. These text files contain PCL (Print Command Language). When I import a new file, it is being truncated by a \0 (NULL Terminator character). Because PCL files contain graphic images randomly throughout everything I import is truncated at the first bitmap image because the bitmap images start with NULL.

This is the exact issue as seen here: Displaying Raw Data From Image File Using TextBox or RichTextBox?

Unfortunately I can't comment on this thread though because of my low (newbie) reputation (need 15 rep). Also can't paste a screenshot (need 10 rep).


Here is how Notepad++ displays the information:


Here is how my RichTextBox displays this same information:


Here is why this is a problem (Zoomed out):

The raster data is right between two sections of data I need (The PCL). All of the information below the raster data won't pull in.


Here is what I have tried (Note: I am using a custom RichTextBox, but this shouldn't affect anything since it's just a RichTextBox with Drag/Drop functionality):

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

This just causes a chain of 2048 number "1" characters with none of the text file's data pulling in. Any help is much appreciated.

Whatever I do, I would like to preserve my current drag/drop functionality:

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:


Rather than trying to read the file data into a string, as Jim Mischel answered it should be read into a byte array and processed.

Here's a static class that will read a file into a byte array, and process it based on a dictionary lookup. I've prepopulated the dictionary with "\00" for non-printable ASCII characters and all values over 127.

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

Edit since you want to use this with your custom drag-and-drop code, the usage should be:

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



回答2:


First of all, you don't want ASCII encoding. ASCII is a 7-bit encoding. Any characters read that have the high bit set (i.e. character codes 128 through 255) are converted to question marks by the decoder. So reading binary data as ASCII is going to destroy your data.

Second, the rich text box uses a Windows control under the hood, and that control is designed to work with null-terminated strings. So it's going to truncate the text the first time it sees a '\0' character. If you want to display binary data in an edit control, you need to modify the text to be displayed.

Your "text" files really aren't text, as they contain binary (i.e. non-human-readable) data. Your best bet is to open the file and read the entire thing into a memory buffer as binary. That is:

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

Then, if you want to display the data in a text control, you have to create a string that represents the data. I would suggest something like:

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.
        }
    }
}

Rather than building a big switch statement, you might want to build a lookup table that has the strings for each of the values you want to convert. A dictionary would probably be best. Something like:

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

Then your loop could do this:

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


来源:https://stackoverflow.com/questions/24268672/cant-see-past-the-null-terminator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!