Мне неловко задавать этот вопрос, поскольку я чувствую, что я уже должен знать. Однако, учитывая, что я не ... Я хочу знать, как читать большие файлы с диска в базу данных, не получая исключение OutOfMemory. В частности, мне нужно загрузить CSV (или действительно файлы с разделителями табуляции).
Я экспериментирую с CSVReader
и, в частности, с этим примером кода, но я уверен, что делаю это неправильно. Некоторые из их других образцов кодирования показывают, как вы можете читать потоковые файлы любого размера, что в значительной степени то, что я хочу (только мне нужно читать с диска), но я не знаю, какой тип IDataReader
я мог бы создать, чтобы это разрешить ,
Я читаю прямо с диска, и я стараюсь, чтобы у меня не хватило времени на чтение, слишком быстро считывая слишком много данных. Я не могу не думать о том, что я должен использовать BufferedFileReader
или что-то подобное, где я могу указать на местоположение файла и указать размер буфера, а затем CsvDataReader
ожидает, что IDataReader
будет первым параметром, он может просто использовать это. Пожалуйста, покажите мне ошибку в моих путях, позвольте мне избавиться от моего метода GetData
с его произвольным механизмом блокировки файлов и помочь мне справиться с этой основной проблемой.
private void button3_Click(object sender, EventArgs e)
{
totalNumberOfLinesInFile = GetNumberOfRecordsInFile();
totalNumberOfLinesProcessed = 0;
while (totalNumberOfLinesProcessed < totalNumberOfLinesInFile)
{
TextReader tr = GetData();
using (CsvDataReader csvData = new CsvDataReader(tr, '\t'))
{
csvData.Settings.HasHeaders = false;
csvData.Settings.SkipEmptyRecords = true;
csvData.Settings.TrimWhitespace = true;
for (int i = 0; i < 30; i++) // known number of columns for testing purposes
{
csvData.Columns.Add("varchar");
}
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(@"Data Source=XPDEVVM\XPDEV;Initial Catalog=MyTest;Integrated Security=SSPI;"))
{
bulkCopy.DestinationTableName = "work.test";
for (int i = 0; i < 30; i++)
{
bulkCopy.ColumnMappings.Add(i, i); // map First to first_name
}
bulkCopy.WriteToServer(csvData);
}
}
}
}
private TextReader GetData()
{
StringBuilder result = new StringBuilder();
int totalDataLines = 0;
using (FileStream fs = new FileStream(pathToFile, FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
string line = string.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.StartsWith("D\t"))
{
totalDataLines++;
if (totalDataLines < 100000) // Arbitrary method of restricting how much data is read at once.
{
result.AppendLine(line);
}
}
}
}
}
totalNumberOfLinesProcessed += totalDataLines;
return new StringReader(result.ToString());
}
Вероятно, это не тот ответ, который вы ищете, но для этого был разработан BULK INSERT .
На самом деле ваш код считывает все данные из файла и TextReader
в TextReader
(в памяти). Затем вы читаете данные из TextReader
для сохранения сервера.
Если данные настолько велики, размер данных в TextReader
вызвал TextReader
памяти. Пожалуйста, попробуйте этот путь.
1) Чтение данных (каждая строка) из файла.
2) Затем вставьте каждую строку в сервер.
Проблема с памятью будет решена, потому что только каждая запись в памяти во время обработки.
Псевдокод
begin tran
While (data = FilerReader.ReadLine())
{
insert into Table[col0,col1,etc] values (data[0], data[1], etc)
}
end tran