有效的方式传输许多二进制文件到SQL Server数据库



我们需要一个Winforms应用程序从本地文件系统(或网络位置)读取数千个文件并将它们存储在数据库中。

我想知道加载文件的最有效方法是什么?总共可能有很多gb的数据。

File.ReadAllBytes当前被使用,但随着计算机内存耗尽,应用程序最终锁定。

当前代码循环遍历包含用于读取二进制数据的文件路径的表:

protected CustomFile ConvertFile(string path)
{
    try
    {
        byte[] file = File.ReadAllBytes(path);
        return new CustomFile { FileValue = file };
    }
    catch
    {
        return null;
    }
}

数据然后保存到数据库(SQL Server 2008 R2或2012)使用NHibernate作为ORM

首先,让我声明一下,我的知识是在。NET 4.0之前,所以这些信息可能已经过时了,因为我知道他们将在这方面进行改进。

不要使用File。ReadAllBytes读取大文件(大于85kb),特别是当您依次读取许多文件时。我再说一遍,不要。

使用流和BinaryReader之类的东西。用阅读来缓冲你的阅读。即使这听起来效率不高,因为您不会通过单个缓冲区来消耗CPU,但如果您使用ReadAllBytes来这样做,它根本不会像您发现的那样工作。

这样做的原因是因为ReadAllBytes读取字节数组中的整个内容。如果字节数组在内存中>85Kb(还有其他考虑因素,如数组元素的数量),它将进入大对象堆,这很好,但是,LOH不会移动内存,也不会对释放的空间进行碎片整理,因此,简化,这可能发生:

  • 读取1GB文件,您在LOH中有1GB块,保存该文件。(无GC循环)
  • 读取1.5GB的文件,您请求1.5GB的内存块,它进入LOH的末端,但是假设您得到一个GC周期,因此您之前使用的1GB块被清除,但现在您有一个2.5GB内存块,第一个1GB空闲。
  • 读取一个1.6GB的文件,开始的1GB空闲块不起作用,所以分配器转到最后。现在你有一个4.1GB的内存块。
  • 重复。

你正在耗尽内存,但你肯定没有真正使用它,碎片可能会杀死你。此外,如果文件非常大(我认为Windows 32位的进程空间是2GB?),您实际上可能会遇到真正的OOM情况。

如果文件不是有序的或相互依赖的,那么通过使用BinaryReader缓冲来读取它们的几个线程可能会完成这项工作。

引用:http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/learning-memory-management/memory-management-fundamentals

https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/

如果你有很多文件,你应该一个一个地读。

如果你有大文件,并且数据库允许,你应该把它们一块一块地读入缓冲区,然后一块一块地写入数据库。如果您使用File.ReadAllBytes,当文件太大而无法装入运行时内存时,您可能会得到OutOfMemoryException。上限小于2gib,如果应用程序运行一段时间后内存被碎片化,则上限更小。

最新更新