我想创建一个简单的文本文件查看器,我希望它能够处理大文件(可能比计算机的内存大)。
我知道我需要实现类似滑动缓冲区的东西,它将包含文件的当前可见部分。主要问题是确定行和文件偏移之间的关系。如果我只需要能够按行导航,我只需要一个链接的行列表,并在行上/行下行,只需从文件中读取新行。但是,当我还想去,比如文件的50%时,我该怎么办?我需要显示从文件的一半开始的行,所以如果文件长度为10000字节,我会寻找字节5000,寻找换行符并从那里显示内容。问题是,我不知道在寻找这样的时候我在做什么。
所以我想知道的是什么是一个合适的数据结构,用于将这几行保留在内存中(将在屏幕上绘制的那些)。
请记住,我不需要编辑文件,只需查看它们,因此我不需要关心所选方法的效率。
答案 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();
}
}
}
也许至少会让你朝着正确的方向前进。