2010-06-22 49 views
1

尝试生成某些HTML报告时,出现'System.OutOfMemoryException'。重构 - System.OutOfMemoryException

我该如何重新设定这个值,以便将其缓冲到文件中,而不是将其全部读取到内存中,然后写入文件。

数据表中会有超过2000多条记录向上,并且已经有2000行的内存不足。

DetailsUpdateTemplate包含一个多行html代码片段。我假设我正在创建一个很大的字符串。串联次数超出屈指可数的字符串时

我使用C#,.NET 3.5

internal static String SaveARSUpdateHTML(DataTable table, string fileName) 
    { 
     int recordCount = table.Rows.Count; 

     Dictionary<String, object> templateCols = new Dictionary<string, object>(); 

     templateCols["Track"] = table.TableName; 
     templateCols["ProdDate"] = DateTime.Now.ToShortDateString(); 
     templateCols["ProdTime"] = DateTime.Now.ToShortTimeString(); 
     templateCols["TotalRecords"] = recordCount; 

     String detailOutput = String.Empty; 
     for (int i = 0; i < table.Rows.Count; i++) 
     { 
      int ResultID = i + 1; 
      DataRow row = table.Rows[i]; 
      String ReportDetails = DetailsUpdateTemplate; 
      ReportDetails = ReportDetails.Replace(String.Format("{{{0}}}", "ResultID"), ResultID.ToString()); 
      foreach (DataColumn column in table.Columns) 
      { 
       String value = row[column.ColumnName].ToString(); 
       if (column.ColumnName.Equals("TF")) 
       { 
        String display = value.Equals("no", StringComparison.CurrentCultureIgnoreCase) ? "none" : "block"; 
        ReportDetails = ReportDetails.Replace(String.Format("{{{0}}}", "SuppressNewAddr"), display); 
       } 

       ReportDetails = ReportDetails.Replace(String.Format("{{{0}}}", column.ColumnName), value); 
      } 

      detailOutput += ReportDetails; 
     } 

     templateCols["ReportDetails"] = detailOutput; 

     String masterOut = MasterUpdateTemplate; 
     foreach (KeyValuePair<string, object> pair in templateCols) 
     { 

      masterOut = masterOut.Replace(String.Format("{{{0}}}", pair.Key), pair.Value.ToString()); 
     } 

     String outputFile = String.Format("{0}.htm", fileName); 
     using (StreamWriter sw = new StreamWriter(outputFile)) 
     { 
      sw.Write(masterOut); 
     } 

     return outputFile; 
    } 
+1

您没有提供代码的相关部分。所有这些代码正在做的是修改内存中已经有**的一些数据以将其保存到文件中。 'DataTable'是内存中的。所以,而不是使用'DataTable'使用SqlDataReader并直接流到文件。 – 2010-06-22 21:21:27

+0

我正在从一个不同的库中传递一个DataTable。我无法改变输入行为。 – 2010-06-22 21:28:00

回答

8

使用StringBuilders。

特别是在这里:

detailOutput += ReportDetails; 

而且使用DataReader。 DataReader将返回支持IDataRecord的记录,该记录具有与DataRow类似的接口。

当我在ASP.NET中使用DataTables和DataSet时,您正在打击OOM的行数大致相同,在ASP.NET中使用DataTables和DataSets时,工作进程在回收内存使用过多之前内存有限。这就是为什么我一直在尽我所能积极地切换到DataReader。

更新:

DataReader的解决方案会是什么样子......(TableReaders存在,但不会买你的东西在内存保护方面,你只希望得到更多的类似的DataReader接口)

internal static String SaveARSUpdateHTML(DbDataReader myReader, string fileName) 
    { 

if (myReader.HasRows) 
    while (myReader.Read()) 
    { 
     object something = myReader["TF"]; 
    } 

else 
    Console.WriteLine("No rows returned."); 

myReader.Close(); 
+0

Matthew,我怀疑是一个错字:“当我使用DataTables和DataReaders”应该是“...和DataAdapters”? – 2010-06-22 21:27:33

+0

@亨克霍尔特曼。是的。数据前缀过多。 – MatthewMartin 2010-06-22 21:51:16

+0

StringBuilder可以/应该在这里使用,不仅用于连接,还用于主循环中的Replace()。虽然阅读器/适配器与该特定代码无关。 – 2010-06-22 22:03:11

3

使用StringBuilder而不是字符串

1

除了明显的StringBuilder

为什么不直接将此流式传输到文件,只是每次处理一行,然后每行进行一次模板替换。这样你甚至不需要在整个内存中保存整个报告。

巨大模板上的替换代码将成为内存管理员。

相关问题