【问题标题】:File viewer with sliding buffer带有滑动缓冲区的文件查看器
【发布时间】:2010-05-24 11:08:46
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: c# winforms file text buffer


    【解决方案1】:

    如果您正在通过 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();
            }   
        }   
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-20
      • 1970-01-01
      • 2013-09-26
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      • 2012-05-12
      • 2014-12-11
      相关资源
      最近更新 更多