带滑动缓冲区的文件查看器

时间:2010-05-24 11:08:47

标签: c# winforms file text buffer

我想创建一个简单的文本文件查看器,我希望它能够处理大文件(可能比计算机的内存大)。

我知道我需要实现类似滑动缓冲区的东西,它将包含文件的当前可见部分。主要问题是确定行和文件偏移之间的关系。如果我只需要能够按行导航,我只需要一个链接的行列表,并在行上/行下行,只需从文件中读取新行。但是,当我还想去,比如文件的50%时,我该怎么办?我需要显示从文件的一半开始的行,所以如果文件长度为10000字节,我会寻找字节5000,寻找换行符并从那里显示内容。问题是,我不知道在寻找这样的时候我在做什么。

所以我想知道的是什么是一个合适的数据结构,用于将这几行保留在内存中(将在屏幕上绘制的那些)。

请记住,我不需要编辑文件,只需查看它们,因此我不需要关心所选方法的效率。

1 个答案:

答案 0 :(得分:0)

如果您通过FileStream读取定义的字节块,则可以跟踪最后读取的字节,以便知道接下来要从哪里读取以从文件中读取更多数据块。 FileStream公开了Read(),它允许您指定偏移字节(要开始的位置)以及一次要读取的字节数。

读入字节后,您可以使用解码器将它们解码为UTF8,然后使用它检索char数组。所有这些都应该初始化您的初始数据。我会做什么,因为这将显示在某处是与滚动绑定的设置事件处理程序。当你开始向下滚动时,你可以从内存中删除顶行(同时在删除前计算它们的字节,这样你就可以动态读取下一个具有相同精确大小的字节)并在底部添加新行。同样向上滚动。

如果您想要找出一半的数据,那么您可以尝试使用文本文件路径上的FileInfo对象,然后使用Length()方法返回字节数。由于流以字节为单位处理,因此在尝试读取百分比时会派上用场。您可以使用它来定义要读入的字节数。您必须读取数据以确定换行符的位置,并将您读取的最后一个字节设置为CR-LF,以便在再次检索数据时在下一行读取。

以下是我从文件中读取预定义字节数的方法。

public static LastByteRead = 0; // keep it zero indexed

public String[] GetFileChunk( String path, long chunkByteSize )
{
    FileStream fStream;
    String[] FileTextLines;
    int SuccessBytes = 0;
    long StreamSize;
    byte[] FileBytes;
    char[] FileTextChars;
    Decoder UtfDecoder = Encoding.UTF8.GetDecoder();
    FileInfo TextFileInfo = new FileInfo(path);

    if( File.Exists(path) )
    {
        try {
            StreamSize = (TextFileInfo.Length >= chunkByteSize) ? chunkByteSize : TextFileInfo.Length;
            fStream = new FileStream( path, FileMode.Open, FileAccess.Read );
            FileBytes = new byte[ StreamSize ];
            FileTextChars = new char[ StreamSize ]; // this can be same size since it's UTF-8 (8bit chars)

            SuccessBytes = fStream.Read( FileBytes, 0, (Int32)StreamSize );

            if( SuccessBytes > 0 )
            {
                UtfDecoder.GetChars( FileBytes, 0, StreamSize, FileTextChars, 0 );
                LastByteRead = SuccessBytes - 1;

                return 
                    String.Concat( fileTextChars.ToArray<char>() ).Split('\n');
            }

            else
                return new String[1] {""};
        }

        catch {
            var errorException = "ERROR: " + ex.Message;
            Console.Writeline( errorException );
        }

        finally {
            fStream.Close();
        }   
    }   
}

也许至少会让你朝着正确的方向前进。