如果有一个csv文件,其数据会不时增加。现在我需要做的是阅读最后30,000行。
代码:
string[] lines = File.ReadAllLines(Filename).Where(r => r.ToString() != "").ToArray();
int count = lines.Count();
int loopCount = count > 30000 ? count - 30000 : 0;
for (int i = loopCount; i < lines.Count(); i++)
{
string[] columns = lines[i].Split(',');
orderList.Add(columns[2]);
}
工作正常,但问题是
File.ReadAllLines(Filename)
阅读导致性能不足的完整文件。我想要的东西只能读取最后30,000行迭代整个文件。
PS:我正在使用.Net 3.5。 Files.ReadLines()不存在于.Net 3.5
中答案 0 :(得分:4)
您可以使用File.ReadLines()
方法而不是File.ReadAllLines()
来自MSDN:File.ReadLines()
ReadLines 和 ReadAllLines 方法的不同之处如下:
使用ReadLines时,可以先开始枚举字符串集合 整个系列归还;当你使用ReadAllLines时,你必须 在您可以访问之前等待返回整个字符串数组 数组。因此,当您使用非常大的文件时, ReadLines 可以提高效率。
解决方案1 :
string[] lines = File.ReadAllLines(FileName).Where(r => r.ToString() != "").ToArray();
int count = lines.Count();
List<String> orderList = new List<String>();
int loopCount = count > 30000 ? 30000 : 0;
for (int i = count-1; i > loopCount; i--)
{
string[] columns = lines[i].Split(',');
orderList.Add(columns[2]);
}
解决方案2:如果您正在使用.NET Framework 3.5,如下面的评论中所述,您不能使用File.ReadLines()
方法,因为它是.NET 4.0
以后的。{ / p>
您可以使用StreamReader,如下所示:
List<string> lines = new List<string>();
List<String> orderList = new List<String>();
String line;
int count=0;
using (StreamReader reader = new StreamReader("c:\\Bethlehem-Deployment.txt"))
{
while ((line = reader.ReadLine()) != null)
{
lines.Add(line);
count++;
}
}
int loopCount = (count > 30000) ? 30000 : 0;
for (int i = count-1; i > loopCount; i--)
{
string[] columns = lines[i].Split(',');
orderList.Add(columns[0]);
}
答案 1 :(得分:2)
您可以使用File.ReadLines
,因为您可以在返回整个集合之前开始枚举字符串集合。
之后,您可以使用linq
让事情变得更加轻松。 Reverse
将颠倒收集顺序,Take
将采用n
个项目。现在再次添加Reverse
以获取原始格式的最后n
行。
var lines = File.ReadLines(Filename).Reverse().Take(30000).Reverse();
如果您使用的是.NET 3.5或更早版本,则可以创建自己的方法,其工作方式与File.ReadLines
相同。以下是@Jon
public IEnumerable<string> ReadLines(string file)
{
using (TextReader reader = File.OpenText(file))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
现在你可以使用linq
来完成这个函数,就像上面的语句一样。
var lines = ReadLines(Filename).Reverse().Take(30000).Reverse();
答案 2 :(得分:1)
问题在于您不知道从哪里开始读取文件以获取最后30,000行。除非您想要保持单独的线偏移索引,否则您可以从开始计数行读取文件,仅保留最后30,000行,或者您可以从末尾计数行向后开始。如果文件非常大并且您只需要几行,则最后一种方法可以有效。但是,30,000似乎不是“几行”所以这里是一种从一开始就读取文件并使用队列来保留最后30,000行的方法:
var filename = @" ... ";
var linesToRead = 30000;
var queue = new Queue<String>();
using (var streamReader = File.OpenText(fileName)) {
while (!streamReader.EndOfStream) {
queue.Enqueue(streamReader.ReadLine());
if (queue.Count > linesToRead)
queue.Dequeue();
}
}
现在您可以访问queue
中存储的行。此类实现IEnumerable<String>
,允许您使用foreach
来迭代这些行。但是,如果您想要随机访问,则必须使用ToArray
方法将队列转换为数组,这会给计算增加一些开销。
此解决方案在内存方面效率很高,因为最多需要将30,000行保留在内存中,垃圾收集器可以在需要时释放任何额外的行。使用File.ReadAllLines
会立即将所有行拉入内存,这可能会增加进程所需的内存。
答案 3 :(得分:0)
或者我对此有不同的想法。
尝试将csv拆分为A-D,E-G等类别.... 并获取您需要的第一个字符。
或者您可以使用entites分数来分割数据。例如,每个文件将包含15.000个entites。还有一个文本文件,其中包含有关入侵和位置的微小数据,如:
Txt文件:
entitesID | inWhich.Csv
....