从StreamReader批量读取

tt2*_*tt2 4 c# streamreader

尝试通过StreamReader将800MB文本文件加载到DataTable时,我遇到了OutOfMemory Exceptions.我想知道是否有办法从内存流中批量加载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;
}
Run Code Online (Sandbox Code Playgroud)

这是返回的错误:

"System.OutOfMemoryException:类型'System.OutOfMemoryException'的异常被抛出.
在System.String.Split(Char []分隔符,Int32计数,StringSplitOptions选项)
处于System.String.Split(Char [] separator}
处于Harvester.Config .PopulateDataTableFromText(DataTable dt,String txtSource)在C:...."

关于将数据直接加载到SQL中的建议 - 当谈到C#时,我有点像菜鸟,但我认为这基本上就是我在做什么?SqlBulkCopy.WriteToServer获取我从文本文件创建的DataTable并将其导入sql.有没有更容易的方法来做到这一点,我错过了?

编辑:哦,我忘了提 - 这段代码不会在与SQL Server相同的服务器上运行.数据文本文件位于服务器B上,需要写入服务器A中的表.是否排除使用bcp?

LBu*_*kin 5

您是否考虑过将数据直接加载到SQL Server中,然后在数据库中对其进行操作?数据库引擎已经设计为以有效的方式执行大量数据的操作.这可能会产生更好的整体结果,并允许您利用数据库和SQL语言的功能来完成繁重的工作.这是旧的"更聪明,更努力"的原则.

有许多不同的方法可以将数据加载到SQL Server中,因此您可能需要检查这些方法以查看是否适合.如果您使用的是SQLServer 2005或更高版本,并且您确实需要对C#中的数据进行一些操作,则可以始终使用托管存储过程.

这里需要注意的OutOfMemoryException是,这有点误导.内存不仅仅是你拥有的物理内存量.你可能耗尽的是可寻址的内存.这是一个非常不同的事情.

将大文件加载到内存并将其转换为内存时,DataTable可能需要的不仅仅是800Mb来表示相同的数据.由于32位.NET进程仅限于2Gb的可寻址内存,因此您可能永远无法在一个批处理中处理此数量的数据.

您可能需要做的是以流方式处理数据.换句话说,不要尝试将其全部加载DataTable到SQLServer中然后批量插入.而是以块的形式处理文件,一旦完成它们就清除先前的行集.

现在,如果您可以访问具有大量内存的64位计算机(以避免VM抖动)和64位.NET运行时的副本,那么您可以在不更改的情况下运行代码.但我建议做出必要的改变,因为它甚至可以在那种环境下提高性能.