我们要求Winforms应用程序从本地文件系统(或网络位置)读取数千个文件并将它们存储在数据库中。
我想知道加载文件最有效的方法是什么?总共可能有数GB的数据。
当前使用了 File.ReadAllBytes
但是当计算机的内存用完时,应用程序最终会锁定。
当前代码循环遍历包含文件路径的表,用于读取二进制数据:
protected CustomFile ConvertFile(string path)
{
try
{
byte[] file = File.ReadAllBytes(path);
return new CustomFile { FileValue = file };
}
catch
{
return null;
}
}
然后使用NHibernate作为ORM将数据保存到数据库(SQL Server 2008 R2或2012)。
答案 0 :(得分:1)
首先,请允许我说明我的知识是在.NET 4.0之前,所以这些信息可能已经过时,因为我知道他们将在这方面做出改进。
不要使用File.ReadAllBytes来读取大文件(大于85kb),特别是当您按顺序对多个文件执行操作时。我再说一遍,不要。
使用类似流和BinaryReader.Read的内容来缓冲您的阅读。即使这听起来效率不高,因为你不会通过单个缓冲区爆破CPU,如果用ReadAllBytes进行,它就不会像你发现的那样工作。
原因是因为ReadAllBytes读取字节数组中的整个内容。如果mem中的那个字节数组是> 85Kb(还有像数组元素这样的其他注意事项),它会进入大对象堆,这很好,但是,LOH不会移动内存,也不会对释放的空间进行碎片整理,所以,简化,这可能发生:
你的内存不足,但你肯定没有真正使用它,碎片可能会让你失望。如果文件非常大(我认为Windows 32位的进程空间是2GB?),你实际上可以实现真正的OOM情况。)
如果文件没有被排序或相互依赖,那么通过使用BinaryReader缓冲读取它们的几个线程就可以完成工作。
参考文献:
https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/
答案 1 :(得分:0)
如果你有很多文件,你应该逐一阅读。
如果你有大文件,并且数据库允许它,你应该逐块读取它们到缓冲区并逐块写入数据库。如果使用File.ReadAllBytes
,当文件太大而无法放入运行时的内存时,可能会得到OutOfMemoryException
。上限小于2 GiB,当应用程序运行一段时间内存碎片时,上限更小。