读取4000个文件后抛出System.OutOfMemoryException

ami*_*ina 3 c# entity-framework sql-server-2012

我们要进口52000个文件(.pdf,.xls,.doc...等)到SQL Server 2012数据库.

我有一个Dossier_fichier.txt包含文件名称的文件.我将这些名称加载到一个集合中,然后循环遍历此集合,我尝试在direcotry中找到这些文件PiecesJointes并将它们转换为字节并使用以下代码将它们插入到数据库中:

var dossierFichiers = addOrUpdateHelper.ReadEntities<DossierFichier, DossierFichierMap>("dossier_fichier.txt").ToArray();
// (2) Parcourir toutes les instances de DossierFichier chargées + Lire le fichier référencé + Le charger dans la propriété Fichier
var dirPath = System.IO.Path.Combine(Environment.CurrentDirectory, "piecesJointes");
var nbfichier = 0;

foreach (var df in dossierFichiers) {
    try {
        var path = System.IO.Path.Combine(dirPath, string.Concat( df.Code,"_", df.Nom));
        df.Fichier = File.ReadAllBytes(path);
        context.DossierFichier.Add(df);
        context.SaveChanges();

        Logger.Info("Le fichier {0} a été inséré", df.Nom);

        nbfichier++;
    } catch (FileNotFoundException ex) {
        Logger.Error("Fichier {0} : {1}", df.Nom, ex.Message);
    } catch (Exception ex) {
        Logger.Error("Fichier {0} : {1}",df.Nom, ex.Message);
    }
}
Run Code Online (Sandbox Code Playgroud)

OutOFMemoryException插入4000个文件后我得到了一个,花了很多时间(60个小时).请问你能不帮我插入所有这些文件OutOfmemoryException,如何更快地插入?

das*_*ght 5

看起来您的代码具有O(n 2)性能,因为它将所有文件内容保存在内存中.

  • 循环的第一次迭代会保存您添加的第一个对象
  • 第二次迭代保存第二个对象并刷新第一个对象
  • 第三次迭代保存第三个对象并刷新前两个对象
  • ... 等等
  • 第N次迭代插入第N个对象,并刷新先前插入的N-1个对象

您应该能够通过将更新"批处理"来解决这个问题:

  • 添加到目前为止已插入的对象数量
  • 不要context.SaveChanges();马上打电话
  • 当插入的对象数达到100时,调用context.SaveChanges();,然后context用新实例替换.

这将确保所有对象仅保存一次,数据库往返次数受到控制,并且内存中永远不会有超过100个对象.

此外,您可以通过粘贴文件来保留文件的内容df.Fichier.这有可能使系统内存不足,因此您应该复制df:

var path = System.IO.Path.Combine(dirPath, string.Concat( df.Code,"_", df.Nom));
var dfCopy = new DossierFichier(df); // Copy df's fields
dfCopy.Fichier = File.ReadAllBytes(path);
context.DossierFichier.Add(dfCopy);
Run Code Online (Sandbox Code Playgroud)