Saving/Loading RichTextBox Content with other data

2019-06-09 20:31发布

问题:

I am currently trying to figure out how to save the content from a RichTextbox into a stream(currently using FileStream) and do this alongside a bunch of other data. Then of course I want to be able to load from this file. I was currently trying to use something along the following lines.

FileStream stream = new FileStream(); //this is actually correctly defined.
ASCIIEncoding encoding = new ASCIIEncoding();

//write Title
byte[] array = encoding.GetBytes(Title);
stream.WriteByte(Convert.ToByte(array.Length));
stream.Write(array, 0, array.Length);

//save textRange
textRange.Save(stream, System.Windows.DataFormats.Rtf);

//write Subtitle
byte[] array = encoding.GetBytes(Subtitle);
stream.WriteByte(Convert.ToByte(array.Length));
stream.Write(array, 0, array.Length);
//ect...and something very similar for Loading a file.

This is basically what I am trying to do. I am actually saving 2 TextRanges and a bunch more Properties. So my problem is that TextRange.Load() reads to the end of the file...making it impossible for me to use that considering I have 2 TextRanges I need to save/load. So here I am trying to come up with another way to be able to save/load the content of a RichTextBox with other data. I dont have to use a Stream. I am pretty much open to any feasible solutions. Thanks in advance!

~Jasson

回答1:

You could load/save to a MemoryStream to solve your issue with reading to the end of the file. It could look like this:

  • Load your file into memory
  • Load the section of that file that is the contents of the richtextbox into a MemoryStream
  • Load the richtextbox contents from that MemoryStream

Or are you wanting to know how you'd create and parse a file to contain different sections for the title, and the contents, and any other fields ?



回答2:

I figured I should post my current solution. It seems to work perfectly fine. Thank you Chris and Ants to the hints on how to go about doing this.

/// <summary>
    /// Reads a TextRange (DataFormats.Rtf) from the stream.
    /// </summary>
    /// <param name="stream">The stream to be read from.</param>
    /// <returns>The TextRange (DataFormats.Rtf) that was read from the stream.</returns>
    public static TextRange ReadTextRange(FileStream stream)
    {
        long startPos = stream.Position;
        int length = -1;
        int count = 0;
        int previousByte = 0;
        int currentByte = 0;
        //set previousByte to give the current one something to compare to
        previousByte = stream.ReadByte();
        //parse the file counting the { and } to find the end of the rtf portion of the file.
        while (count > 0 || length < 1)
        {
            length++;
            stream.Position = startPos + length;
            currentByte = stream.ReadByte();
            if (previousByte != 92) // not '\' so check to see if '{' or '}' is currentByte
            {
                if (currentByte == 123) // '{' increase count
                    count++;
                else if (currentByte == 125) // '}' decrease count
                    count--;
            }
            previousByte = currentByte;
        }
        //save finish position to move to later
        long finishPos = stream.Position;
        //reset stream position to start at beginning of rtf
        stream.Position = startPos;
        //read the rtf portion of the file into a byte[]
        byte[] content = new byte[length];
        stream.Read(content, 0, length);
        //put the byte[] into a memory stream
        MemoryStream memStream = new MemoryStream(content);
        FlowDocument doc = new FlowDocument();
        TextRange range = new TextRange(doc.ContentStart, doc.ContentEnd);
        //have the TextRange read from the memorystream
        range.Load(memStream, System.Windows.DataFormats.Rtf);
        memStream.Close();
        //set the position to after the rtf portion of the file
        stream.Position = finishPos;
        return range;
    }

This ReadTextRange Method is in a StreamHelper class I defined for helping read from a FileStream. So all of this is to load a TextRange that is saved to the FileStream like this...

//save query (TextRange)
        Query.Save(stream, System.Windows.DataFormats.Rtf);

I hope that someone finds this useful if/when they come to a similar problem! :D

EDIT:

I used a profiler and found that this code was not very efficient so I have changed this code to be much more efficient in a few ways.

  1. Instead of using the TextRange and use a byte[] which holds the contents of MemoryStream memStream. This cuts out range.Load which consumes a lot of CPU.

  2. I took out the line stream.Position = startPos + length because I realized it was useless after the first run and also took up a decent amount of CPU. I placed stream.Position--; after the line previousByte = stream.ReadByte();

Also I realized I was being a bad coder and wasn't following MVC by having TextRange, UI element, inside of my data class. Now it has a byte[], which is MUCH better.

EDIT AGAIN:

After a few minutes of having the byte[] instead of the TextRange I realized I had the size of the byte[] so I didn't need to parse it. So instead I save write the byte[] size and then the byte[]. This makes it extremely fast and can read a very large file nearly instantly.