我在尝试通过 StreamReader 将 800MB 文本文件加载到 DataTable 时遇到了 OutOfMemory 异常。我想知道是否有办法从内存流中批量加载DataTable,即从StreamReader读取文本文件的前10,000行,创建DataTable,对DataTable执行一些操作,然后将接下来的10,000行加载到StreamReader中并很快。
我的谷歌在这里没有多大帮助,但似乎应该有一个简单的方法来做到这一点。最终,我将使用 SqlBulkCopy 将 DataTables 写入 MS SQL 数据库,因此,如果有比我所描述的方法更简单的方法,我将感谢您提供正确方向的快速指针。
编辑 - 这是我正在运行的代码:
public static DataTable PopulateDataTableFromText(DataTable dt, string txtSource)
{
StreamReader sr = new StreamReader(txtSource);
DataRow dr;
int dtCount = dt.Columns.Count;
string input;
int i = 0;
while ((input = sr.ReadLine()) != null)
{
try
{
string[] stringRows = input.Split(new char[] { '\t' });
dr = dt.NewRow();
for (int a = 0; a < dtCount; a++)
{
string dataType = dt.Columns[a].DataType.ToString();
if (stringRows[a] == "" && (dataType == "System.Int32" || dataType == "System.Int64"))
{
stringRows[a] = "0";
}
dr[a] = Convert.ChangeType(stringRows[a], dt.Columns[a].DataType);
}
dt.Rows.Add(dr);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
i++;
}
return dt;
}
这是返回的错误:
“System.OutOfMemoryException:引发了“System.OutOfMemoryException”类型的异常。
在 System.String.Split(Char[] 分隔符,Int32 计数,StringSplitOptions 选项)
在 System.String.Split(Char[] 分隔符}
在 C:... 中的 Harvester.Config.PopulateDataTableFromText(DataTable dt, String txtSource)
关于将数据直接加载到 SQL 中的建议 - 对于 C#,我有点菜鸟,但我认为这基本上就是我正在做的事情? SqlBulkCopy.WriteToServer 获取我从文本文件创建的 DataTable 并将其导入到 sql 中。有没有一种更简单的方法可以做到这一点,而我却错过了?
编辑:哦,我忘了提及 - 该代码不会与 SQL Server 在同一台服务器上运行。数据文本文件位于服务器 B 上,需要写入服务器 A 中的表。这是否妨碍使用 bcp?
您是否考虑过将数据直接加载到 SQL Server 中,然后在数据库中进行操作?数据库引擎已经设计为以有效的方式执行大量数据的操作。这可能会产生更好的总体结果,并允许您利用数据库和 SQL 语言的功能来完成繁重的工作。这是旧的“更聪明地工作,而不是更努力地工作”原则。
有许多将数据加载到 SQL Server 的不同方法 http://www.mssqltips.com/tip.asp?tip=1207,因此您可能需要检查这些内容,看看是否有合适的。如果您使用的是 SQLServer 2005 或更高版本,并且确实需要在 C# 中对数据进行一些操作,那么您始终可以使用托管存储过程 http://www.sqlteam.com/article/writing-clr-stored-procedures-in-charp-introduction-to-charp-part-1.
这里需要意识到的是OutOfMemoryException
有点误导。内存不仅仅是您拥有的物理 RAM 的数量 http://blogs.msdn.com/b/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx。你可能用完的是可寻址内存。这是完全不同的事情。
当您将大文件加载到内存并将其转换为DataTable
它可能需要表示相同数据的大小远不止 800Mb。由于 32 位 .NET 进程仅限于不到 2Gb 的可寻址内存,因此您可能永远无法在单个批次中处理如此大量的数据。
您可能需要做的是以流方式处理数据。换句话说,不要尝试将其全部加载到DataTable
然后批量插入到SQLServer。而是分块处理文件,在完成处理后清除先前的行集。
现在,如果您可以访问具有大量内存的 64 位计算机(以避免虚拟机抖动)并且
64 位 .NET 运行时的副本,您可能可以在不更改代码的情况下运行。但我建议无论如何进行必要的更改,因为即使在那种环境下它也可能会提高性能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)