2011-01-24 5 views
0

Я пытаюсь экспортировать данные таблицы SQL в текстовый файл с разделителем '~' в коде C#. Когда данные мелкие, его штраф. Когда он огромен, он выбрасывает исключение из памяти.Экспорт данных таблицы в текстовый файл + C# + SQL Server

Мой код:

public static void DataTableToTextFile(DataTable dtToText, string filePath) 
{ 
    int i = 0; 
    StreamWriter sw = null; 

    try 
    { 
     sw = new StreamWriter(filePath, false); /*For ColumnName's */ 
     for (i = 0; i < dtToText.Columns.Count - 1; i++) 
     { 
      sw.Write(dtToText.Columns[i].ColumnName + '~'); 
     } 
     sw.Write(dtToText.Columns[i].ColumnName + '~'); 
     sw.WriteLine(); /*For Data in the Rows*/ 

     foreach (DataRow row in dtToText.Rows) 
     { 
      object[] array = row.ItemArray; 
      for (i = 0; i < array.Length - 1; i++) 
      { 
       sw.Write(array[i].ToString() + '~'); 
      } 
      sw.Write(array[i].ToString() + '~'); 
      sw.WriteLine(); 
     } 
     sw.Close(); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(""); 
    } 
} 

Есть ли лучший способ сделать это в хранимой процедуре или BCP команды?

+0

вы попробовали написать несколько строк, закрыв затем открытие файла? – griegs

+0

Что огромно? Каков размер набора записей, когда он освобождается? – Rob

ответ

1

Если нет особых причин для использования ~ формат разделителей, вы можете попробовать использовать DataTable функцию WriteXml (http://msdn.microsoft.com/en-us/library/system.data.datatable.writexml.aspx)

Например: dtToText.WriteXml ("C: \ data.xml")

Если вам нужно преобразовать этот текст обратно в DataTable позже вы можете использовать ReadXml (http://msdn.microsoft.com/en-us/library/system.data.datatable.readxml.aspx)

Если вам действительно нужно сделать существующий код работать, я бы, вероятно, попробуйте закрыть и призвание Dispose на StreamWriter в установить интервал, затем снова открыть и добавить к g текст.

0

Я понимаю, что этот вопрос лет, но я недавно испытал подобную проблему. Решение. Вкратце, я думаю, что у вас проблемы с большой кучей объектов Windows. Соответствующая ссылка: https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/

Резюмируя выше статье: При выделении участков памяти более 85K длинной (что вполне вероятно, произойдет за кулисами вашего объекта StreamWriter, если значения в вашем DataTable достаточно велики), они идут на отдельную кучу, большую кучу объектов (LOH). Блоки памяти в LOH освобождаются обычно, когда истекает срок их службы, но куча не уплотняется. В результате получается System.OutOfMemoryException, а не потому, что на самом деле недостаточно памяти, а потому, что в какой-то момент недостаточно памяти .

Если вы используете рамки .NET 4.5.1 или более поздней версии (который не будет работать на Visual Studio 2010 или до, она может работать на VS2012), вы можете использовать эту команду:

System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; 

Эта команда заставляет уплотнение LOH произойти в следующей сборке мусора. Просто поставьте эту команду в качестве первой строки в вашей функции; он будет установлен на CompactOnce каждый раз, когда вызывается эта функция, что вызовет уплотнение LOH в некоторой неопределенной точке после вызова функции.

Если у вас нет .NET 4.5.1, он становится более уродливым. Проблема в том, что выделение памяти не является явным; это, скорее всего, происходит за кулисами в вашем StreamWriter. Попробуйте позвонить GC.Collect(), время от времени заставляя сбор мусора - возможно, каждый третий раз вызывается эта функция.

Предупреждение: многие люди посоветуют вам, что вызов GC.Collect() - это плохая идея и будет замедлять ваше приложение - и они правы. Я просто не знаю, как лучше справиться с этой проблемой.

Смежные вопросы