我正在解析一个 40MB 的 CSV 文件。
它现在工作得很好,而且很容易解析,我唯一的问题是性能,这当然很慢。
我想知道是否有一种方法可以改进这一点,因为我只需要通过我找到的键找到然后停止循环,所以如果条目位于文件的开头,它会很快完成,但如果它在结束需要一段时间。
我可以通过给它一个随机的起始线来平衡它,但算法仍然是 O(n) ......所以我不确定它是否真的值得。
有没有办法改进我的顺序解析算法?
首先:“阅读巨大的 CSV 文件”和“所以我正在解析一个 40MB 的 CSV 文件。”。我这里有 10+ 千兆字节的空间分隔文件 - 你会怎么称呼它们?
另外:文件的大小无关紧要,您通常会逐行处理它们。
我唯一的问题是性能,这当然很慢
定义。你觉得什么是慢?正确完成后解析它们非常快。
我想知道是否有办法改进这一点,因为我只需要通过我找到的键找到然后停止循环,所以如果条目位于文件的开头,它会很快完成,但如果它在结束需要一段时间。
不要使用 CSV 文件?60 多年前,人们为此发明了数据库。
有没有办法改进我的安全解析算法?
你的意思是除了将解析拉到一个单独的线程中,并使用高效的代码(你可能没有 - 没人知道)。
理论上你可以:
在一个线程上读取,具有不错的缓冲区(更少的 IO = 更快)
将字段拆分为线程 2(可选)
使用任务来解析字段(每行每个字段一个),以便您使用所有处理器)。
我目前正在处理一些(大约 10.000 个)文件(遗憾的是,大小为两位数 gigabte)并且......我采用这种方式(必须以特定顺序处理它们)以充分使用我的计算机。
这应该会给你很多 - 说真的,一个 40mb 的文件应该在 0.x 秒 (0.5 - 0.6) 内加载。
仍然是非常低效的。您没有像所有人一样将文件加载到数据库中的任何原因吗?CSV 作为某种传输格式很好,但它作为数据库很糟糕。
当然。
假设您按字母顺序排列。
然后,从中间开始。
每次迭代,移动到顶部或底部的中间;哪个有相应的密钥。
这个算法有 O(log n )。
这被称为“二分搜索”,是“Mike Christianson”在他的评论中所建议的。
为什么不将 csv 转换为普通数据库。即使是 sqlexpress 也可以。
建议您将一个 40Mb 文件分成较小的几个文件。并且使用 Parallel.ForEach可以提高文件处理性能
我相信,这是顺序读取 CSV 文件的最快方法。可能还有其他方法可以从 CSV 中提取数据,但如果您仅限于这种方法,那么此解决方案可能适合您。
const int BUFFER_SIZE = 0x8000; //represents 32768 bytes
public unsafe void parseCSV(string filePath)
{
byte[] buffer = new byte[BUFFER_SIZE];
int workingSize = 0; //store how many bytes left in buffer
int bufferSize = 0; //how many bytes were read by the file stream
StringBuilder builder = new StringBuilder();
char cByte; //character representation of byte
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
do
{
bufferSize = fs.Read(buffer, 0, BUFFER_SIZE);
workingSize = bufferSize;
fixed (byte* bufferPtr = buffer)
{
byte* workingBufferPtr = bufferptr;
while (workingSize-- > 0)
{
switch (cByte = (char)*workingBufferPtr++)
{
case '\n':
break;
case '\r':
case ',':
builder.ToString();
builder.Clear();
break;
default:
builder.Append(cByte);
break;
}
}
}
} while (bufferSize != 0);
}
}
解释:
Filestream
类来完成,它可以访问总是快速的Read()
StringBuilder
因为我们会将字节连接成可用的字符串来测试密钥。StringBuilder 是迄今为止将字节附加在一起并获得可用字符串的最快方法。请注意,此方法与RFC 4180相当抱怨,但如果您处理引号,您可以轻松修改我发布的代码以处理修剪。
您可以将 CSV 加载到 DataTable 并使用比循环更快的可用操作
将其加载到数据库并对其执行操作是另一种选择