我有一个基于文本的数据库,表示按时间戳排序的日志。出于测试目的,我的数据库大约有10,000行,但这个数字可能更大。它的格式为:
primary_key,source_file,line_num
1, cpu.txt, 2
2, ram.txt, 3
3, cpu.txt, 3
我查询数据库,当我读取结果时,我想将实际数据添加到我可以显示的字符串中。上例中的实际数据将是来自cpu.txt的第2行的内容,后面是来自ram.txt的第3行的内容,等等。行内容可能很长。
一个重要的注意事项是每个文件的行号都是有序的。也就是说,下次我在数据库中遇到cpu.txt
条目时,它将以行4
作为行号。但是,我可能会在ram.txt,harddrive.txt,graphics.txt等数千个其他条目之后看到cpu.txt条目。
我考虑过使用以下代码中的内容:
StringBuilder odbcResults = new StringBuilder();
OdbcDataReader dbReader = com.ExecuteReader(); // query database
while (dbReader.Read())
{
string fileName = dbReader[1].ToString(); // source file
int fileLineNum = int.Parse(dbReader[2].ToString()); // line number in source file
odbcResults.Append(File.ReadLines(fileName).Skip(fileLineNum).First());
}
但是,每次迭代后,File.ReadLines()
都不会想要处理它的TextReader吗?不是很有效率?
我也有这个想法,为Dict中需要读取的每个文件保留一个StreamReader:
Dictionary<string, StreamReader> fileReaders = new Dictionary<string, StreamReader>();
StringBuilder odbcResults = new StringBuilder();
OdbcDataReader dbReader = com.ExecuteReader();
while (dbReader.Read())
{
string fileName = dbReader[1].ToString(); // source file
int fileLineNum = int.Parse(dbReader[2].ToString()); // line number in source file
if (!fileReaders.ContainsKey(fileName))
{
fileReaders.Add(fileName, new StreamReader(fileName));
}
StreamReader fileReader = fileReaders[fileName];
// don't have to worry about positioning? Lines consumed consecutively
odbcResults.Append(fileReader.ReadLine());
}
// can't forget to properly Close() and Dispose() of all fileReaders
您是否同意以上任何一个例子,或者是否有更好的方法?
对于第二个例子,我假设StreamReader将记住它的最后位置 - 我相信它会保存在BaseStream中。
我已阅读How do I read a specified line in a text file?,Read text file at specific line,StreamReader and seeking(第一个答案提供了指向具有定位功能的自定义StreamReader类的链接,但我只知道我需要的行号是,而不是抵消)但不要认为他们具体回答我的问题。
答案 0 :(得分:2)
如果您可以保证您的行引用在文件中是严格顺序的(即,在您要求第n行后总是要求第n + 1行),那么您可以选择保留StreamReader
字典实例看起来是个好主意。
如果您可能要求行n,那么行n + x(其中x是某个正数&gt; = 1),然后我将StreamReader
包裹在跟踪当前行的对象中number并有一个方法GetLine(int lineNo)
,它将返回请求的行号。假设请求的行号大于当前行号(不允许向后读取)。
你不必担心定位。这是为你处理的,因为你正在顺序阅读。
答案 1 :(得分:1)
听起来你似乎想要在内存中(用于在文本框中显示)用户选择的所有内容 - 因此无论如何这是可行的自然边界。我建议采用以下方法:
此时,应该完全填充“最终数据阵列”。您只需要一次打开一个文件,而您永远不需要读取整个文件。我认为这比打开文件字典更简单 - 除了其他任何东西,它意味着你可以为每个文件使用using
语句,而不是必须手动处理所有关闭。
它确实意味着一次在内存中包含所有数据库元数据条目,但可能每个元数据条目都小于您需要在内存中最终需要的结果数据,以便将结果显示给用户。
即使您将多次查看数据库元数据条目,也会发生在内存中。与文件系统或数据库的IO相比,它应该是无关紧要的。
另一种方法是在读取时按文件名对元数据条目进行分组,将索引保留为元数据条目的一部分。