C# C:读取巨大的CSV文件
我正在解析一个40MB的CSV文件 它现在工作得很好,而且很容易解析,我唯一的问题是性能,这当然是相当慢的 我想知道是否有一种方法可以改进这一点,因为我只需要按键查找,然后停止循环,因此,如果条目位于文件的开头,它会很快完成,但如果位于结尾,则需要一段时间 我可以通过给它一个随机的起始线来平衡这一点,但算法仍然是在。。。所以我不确定这是否真的值得C# C:读取巨大的CSV文件,c#,csv,C#,Csv,我正在解析一个40MB的CSV文件 它现在工作得很好,而且很容易解析,我唯一的问题是性能,这当然是相当慢的 我想知道是否有一种方法可以改进这一点,因为我只需要按键查找,然后停止循环,因此,如果条目位于文件的开头,它会很快完成,但如果位于结尾,则需要一段时间 我可以通过给它一个随机的起始线来平衡这一点,但算法仍然是在。。。所以我不确定这是否真的值得 有什么方法可以改进我的顺序解析算法吗?为什么不将csv转换为普通数据库呢。甚至sqlexpress也可以。当然可以 假设你按字母顺序排列。 然后,从中
有什么方法可以改进我的顺序解析算法吗?为什么不将csv转换为普通数据库呢。甚至sqlexpress也可以。当然可以 假设你按字母顺序排列。 然后,从中间开始。 每次迭代,移动到顶部或底部的中间;哪个有合适的钥匙 该算法具有OLOGN
这就是所谓的二进制搜索,这也是迈克·克里斯汀森在评论中的建议 将建议您将一个40Mb文件拆分为几个较小的文件。
而且使用可以提高文件处理性能首先:读取巨大的CSV文件,因此我正在解析一个40MB的CSV文件。。我这里有10+GB的空间分隔文件-你会怎么称呼这些文件 另外:文件的大小是不相关的,您通常会逐行处理它们 我唯一的问题是性能,这当然是相当缓慢的 定义。你认为什么东西慢?正确完成后,解析它们的速度相当快 我想知道是否有一种方法可以改进这一点,因为我只需要按我找到的键和 然后停止循环,这样,如果条目位于文件的最前端,它就会停止循环 完成得很快,但如果是在最后,则需要一段时间 不使用CSV文件?60多年前,人们为此发明了数据库 有什么方法可以改进我的连续解析算法吗 你的意思是,除了将解析拉到一个单独的线程中,并使用一个可能没有的高效代码之外——没有人知道 理论上你可以: 在一个线程上读取,具有适当的缓冲区更少IO=更快 将字段拆分为线程2(可选) 使用任务来解析字段,每行一个字段,以便使用所有处理器 我目前正在处理大约10000个大小为两位数千兆字节的文件,并且。。。我走这条路,必须按照特定的顺序处理它们,才能充分使用我的电脑 这会给你带来很多好处——说真的,一个40mb的文件应该在0.x秒0.5-0.6内加载
但这仍然是非常低效的。你为什么不像所有人那样将文件加载到数据库中?CSV和某些传输格式一样好,它就像一个数据库。您可以将CSV加载到DataTable中,并使用比循环更快的可用操作
将其加载到数据库并对其执行操作是另一个选项,我相信这是按顺序读取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类来完成,该类提供对始终快速读取的访问
不安全代码。虽然我通常建议不要使用不安全的代码,但在遍历任何类型的缓冲区时,使用指针都会带来加速。
StringBuilder,因为我们将把字节连接到可工作的字符串中,以便对键进行测试。到目前为止,StringBuilder是将字节附加在一起并从中获得可用字符串的最快方法。
请注意,这种方法相当麻烦,但如果您处理引号,您可以轻松修改我发布的代码来处理修剪。如果您可以按该键对文件进行排序,则可以使用二进制搜索来提高速度。首先,对于CSV文件来说,40MB并不是那么大。第二,您目前使用的代码中有哪些显然花费了这么长时间?我不认为它会那么慢,这意味着你要么有不切实际的期望,要么你的代码中有更严重的问题。1秒?你为什么想要比一秒钟更快?我只是想知道是否有可能更快的方法,因为我很好奇-你为什么不发布你的代码,这样人们就可以提出一些建议。说我如何让它跑得更快?不用说它是什么,也没什么好做的。CSV文件是由客户端删除的,他们从excel中导出并定期更新,我可以检查文件的修改日期,如果更新了,我可以创建一个数据库。这是一个解决方案,虽然不是我正在寻找的,但如果CSV变得太慢,我可能会尝试以下方法:啊!有序CSV。。。这是可行的,但是CSV文件没有排序,解析文件以排序可能不值得,因为我可以按照@Lakis所说的那样做。但我喜欢这个主意:我甚至都没有
要知道这是可能的,尽管算法本身仍然在运行,但由于并行性,计算速度会更快:我会试试这个!谢谢如果你的文件是在一个硬盘上,这很可能会减慢速度。虽然这里的所有改进都是有用的,但值得向OP强调的是,在你的具体情况下,这将需要大量的工作才能正确,你会发现,由于你没有足够的数据或处理需求,在几分之一秒的最大值上几乎没有什么改进。最重要的是,这也是我所说的,这实际上需要一个索引和类似数据库的方法——从CSV开始这样做不是正确的方法。我不确定——真的。这在按分和按磅分类中可能是最快的,您忽略了并非所有字段都是字符串的事实,即可能需要额外的转换。最后,你可能会节省很多钱-很少的字符串分裂。我会使用FileStream nie大缓冲区上的BUfferedStream,比如半兆字节,使用字符串拆分,然后从那里获取它——假设大多数字段都被解析,结果被放入一个类中@TomTom我在104MB CSV上做了一些初步测试。我提出解决方案的方式实际上是执行速度最慢的,大约5%。安全代码数组索引和带缓冲流512KB缓冲区的安全代码速度更快,大致相等。我不确定您所指的字符串拆分是什么,因为它是字符串操作,仍然需要转换。这正是我所指的。由于大部分时间将花费在对流和字符串操作上,因此即使节省50%的负载,也不会产生任何有效差异;过早优化。不安全的代码没有真正的收益,我认为没有检查。这在很大程度上取决于解析的复杂程度。