StreamReader and seeking

后端 未结 5 473
庸人自扰
庸人自扰 2020-11-27 06:59

can you use streamreader to read a normal textfile and then in the middle of reading close the streamreader after saving the current position and then open streamreader agai

5条回答
  •  夕颜
    夕颜 (楼主)
    2020-11-27 07:24

    If you want to just search for a start position within a text stream, I added this extension to StreamReader so that I could determine where the edit of the stream should occur. Granted, this is based upon characters as the incrementing aspect of the logic, but for my purposes, it works great, for getting the position within a text/ASCII based file based upon a string pattern. Then, you can use that location as a start point for reading, to write a new file that discludes the data prior to the start point.

    The returned position within the stream can be provided to Seek to start from that position within text-based stream reads. It works. I've tested it. However, there may be issues when matching to non-ASCII Unicode chars during the matching algorithm. This was based upon American English and the associated character page.

    Basics: it scans through a text stream, character-by-character, looking for the sequential string pattern (that matches the string parameter) forward only through the stream. Once the pattern doesn't match the string parameter (i.e. going forward, char by char), then it will start over (from the current position) trying to get a match, char-by-char. It will eventually quit if the match can't be found in the stream. If the match is found, then it returns the current "character" position within the stream, not the StreamReader.BaseStream.Position, as that position is ahead, based on the buffering that the StreamReader does.

    As indicated in the comments, this method WILL affect the position of the StreamReader, and it will be set back to the beginning (0) at the end of the method. StreamReader.BaseStream.Seek should be used to run to the position returned by this extension.

    Note: the position returned by this extension will also work with BinaryReader.Seek as a start position when working with text files. I actually used this logic for that purpose to rewrite a PostScript file back to disk, after discarding the PJL header information to make the file a "proper" PostScript readable file that could be consumed by GhostScript. :)

    The string to search for within the PostScript (after the PJL header) is: "%!PS-", which is followed by "Adobe" and the version.

    public static class StreamReaderExtension
    {
        /// 
        /// Searches from the beginning of the stream for the indicated
        /// . Once found, returns the position within the stream
        /// that the pattern begins at.
        /// 
        /// The string pattern to search for in the stream.
        /// If  is found in the stream, then the start position
        /// within the stream of the pattern; otherwise, -1.
        /// Please note: this method will change the current stream position of this instance of
        /// . When it completes, the position of the reader will
        /// be set to 0.
        public static long FindSeekPosition(this StreamReader reader, string pattern)
        {
            if (!string.IsNullOrEmpty(pattern) && reader.BaseStream.CanSeek)
            {
                try
                {
                    reader.BaseStream.Position = 0;
                    reader.DiscardBufferedData();
                    StringBuilder buff = new StringBuilder();
                    long start = 0;
                    long charCount = 0;
                    List matches = new List(pattern.ToCharArray());
                    bool startFound = false;
    
                    while (!reader.EndOfStream)
                    {
                        char chr = (char)reader.Read();
    
                        if (chr == matches[0] && !startFound)
                        {
                            startFound = true;
                            start = charCount;
                        }
    
                        if (startFound && matches.Contains(chr))
                        {
                            buff.Append(chr);
    
                            if (buff.Length == pattern.Length
                                && buff.ToString() == pattern)
                            {
                                return start;
                            }
    
                            bool reset = false;
    
                            if (buff.Length > pattern.Length)
                            {
                                reset = true;
                            }
                            else
                            {
                                string subStr = pattern.Substring(0, buff.Length);
    
                                if (buff.ToString() != subStr)
                                {
                                    reset = true;
                                }
                            }
    
                            if (reset)
                            {
                                buff.Length = 0;
                                startFound = false;
                                start = 0;
                            }
                        }
    
                        charCount++;
                    }
                }
                finally
                {
                    reader.BaseStream.Position = 0;
                    reader.DiscardBufferedData();
                }
            }
    
            return -1;
        }
    }
    

提交回复
热议问题