У меня есть текстовый файл размером 100 ГБ, который представляет собой дамп BCP из базы данных. Когда я пытаюсь импортировать его с помощью BULK INSERT
, я получаю загадочную ошибку в строке 219506324. Прежде чем решить эту проблему, я хотел бы увидеть эту строку, но, увы, мой любимый метод
import linecache
print linecache.getline(filename, linenumber)
- это бросить MemoryError
. Интересно, что в руководстве говорится , что «Эта функция никогда не вызовет исключение». В этом большом файле он выдает единицу, когда я пытаюсь прочитать строку № 1, и у меня есть около 6 ГБ свободной оперативной памяти. ...
Я хотел бы знать, какой метод наиболее изящен , чтобы добраться до этой недоступной линии. Доступными инструментами являются Python 2, Python 3 и C # 4 (Visual Studio 2010). Да, я понимаю, что всегда могу сделать что-то вроде
var line = 0;
using (var stream = new StreamReader(File.OpenRead(@"s:\source\transactions.dat")))
{
while (++line < 219506324) stream.ReadLine(); //waste some cycles
Console.WriteLine(stream.ReadLine());
}
, что бы сработало, но я сомневаюсь, что это самый элегантный способ.
РЕДАКТИРОВАТЬ: Я жду, чтобы закрыть этот поток, потому что жесткий диск, содержащий файл, сейчас используется другим процессом. Я собираюсь проверить оба предложенных метода и сообщить о времени. Спасибо всем за ваши предложения и комментарии.
Результаты приведены в . Я реализовал методы Габеса и Алекса, чтобы увидеть, какой из них был быстрее. Если я делаю что-то не так, скажи. Я использую 10-миллионную строку в моем 100-гигабайтном файле, используя метод, предложенный Гейбом, а затем метод, предложенный Алекс, который я свободно перевел на C # ... Единственное, что я добавляю от себя, - это сначала чтение в 300 Файл MB помещается в память только для очистки кэша жесткого диска.
const string file = @"x:\....dat"; // 100 GB file
const string otherFile = @"x:\....dat"; // 300 MB file
const int linenumber = 10000000;
ClearHDDCache(otherFile);
GabeMethod(file, linenumber); //Gabe's method
ClearHDDCache(otherFile);
AlexMethod(file, linenumber); //Alex's method
// Results
// Gabe's method: 8290 (ms)
// Alex's method: 13455 (ms)
Реализация метода Гейба выглядит следующим образом:
var gabe = new Stopwatch();
gabe.Start();
var data = File.ReadLines(file).ElementAt(linenumber - 1);
gabe.Stop();
Console.WriteLine("Gabe's method: {0} (ms)", gabe.ElapsedMilliseconds);
Хотя метод Алекса немного сложнее:
var alex = new Stopwatch();
alex.Start();
const int buffersize = 100 * 1024; //bytes
var buffer = new byte[buffersize];
var counter = 0;
using (var filestream = File.OpenRead(file))
{
while (true) // Cutting corners here...
{
filestream.Read(buffer, 0, buffersize);
//At this point we could probably launch an async read into the next chunk...
var linesread = buffer.Count(b => b == 10); //10 is ASCII linebreak.
if (counter + linesread >= linenumber) break;
counter += linesread;
}
}
//The downside of this method is that we have to assume that the line fit into the buffer, or do something clever...er
var data = new ASCIIEncoding().GetString(buffer).Split('\n').ElementAt(linenumber - counter - 1);
alex.Stop();
Console.WriteLine("Alex's method: {0} (ms)", alex.ElapsedMilliseconds);
Так что, если Алекс не захочет комментировать, я отмечу решение Гейба как принятое.