2010-05-24 71 views
0

我想制作一个简单的文本文件查看器,并且希望它能够处理大型文件(可能大于计算机内存)。带滑动缓冲区的文件查看器

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

所以我想知道的是将这几行内容保留在屏幕上的合适数据结构是什么。

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

回答

0

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

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

如果你想弄清楚你的一半数据,那么你可以尝试在文本文件路径上使用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(); 
     } 
    } 
} 

也许这会让你至少在正确的方向。