Работа с файлами большого объема C#

106
16 октября 2019, 00:00

Есть скаченный csv файл объемом 1,5 гигабайта. В нем содержится примерно 120 000 000 строк в формате xxxx,yyyyyy. Из них 100 000 это кривые строки с артефактами, эти строки всегда меньше 11 символов.

Задача состоит следующая: обработать файл, и записать правильные строки в новый csv файл. Код, который я написал, отрабатывает эту операцию примерно за 10 часов.

Можно ли эту процедуру по времени сократить?

string line;
using (var file = new StreamReader(File.OpenRead(@"D:\bzip2\decompressed.csv")))
{
    while ((line = file.ReadLine()) != null)
    {
        if( line.Length == 11 )
        {
            File.AppendAllText(@"D:\bzip2\new.csv", line + Environment.NewLine);
        }
    }
}
Answer 1

Читайте с буфером, пишите с буфером, и всё будет хорошо

string line;
using (var file = new StreamReader(new BufferedStream(File.OpenRead(@"D:\bzip2\decompressed.csv"), 10*1024*1024)))
using(var writer = new StreamWriter(new BufferedStream(File.OpenWrite(@"D:\bzip2\new.csv"), 10*1024*1024)))
{       
    while ((line = file.ReadLine()) != null)
    {
        if (line.Length == 11)          
            writer.WriteLine(line);
    }
}
Answer 2

Скорее всего низкая скорость связана с вызовом File.AppendAllText. Этот метод каждый раз будет открывать файл, перемещать указатель в его конец, дописывать текст и закрывать файл.

Все операции, кроме дописывания можно выполнить один раз, а не для каждой строки.

const string infile = @"D:\bzip2\decompressed.csv";
const string outfile = @"D:\bzip2\new.csv";
using (var in = new StreamReader(File.OpenRead(infile))
using (var out = new StreamWriter(File.OpenWrite(outfile))
{
    string line;
    while ((line = in.ReadLine()) != null)
    {
        if(line.Length >= 11)
            out.WriteLine(line);
    }
}
Answer 3
Важный вопрос:

цсв упрощенной формы, или же имеет "сложные ячейки" (которые имеют внутри ячейки делимитер/ переход на следующую строку)?

Если таковые имеются, то твое решение НЕРАБОЧЕЕ.

Как и советы даные мной ниже. Как и все другие ответы на даный момент.

Мой ответ базируется на отсутствии сложных ячеек:

Тебе нужно сделать буфер чтения в виде нескольких мегабайт текста и обрабатывать именно этот текст.

Если ты делаешь построчно у тебя выходит слишком много операций чтения/записи совсем маленькими кусками. Из-за этого и медленная обработка.

Вот пример кода для чтения файла с буфером через стрим:

using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
    }
}

код взят отсюда

Так же оптимизируй операцию записи. Запись для такого размера файла можно делать всего 1-2 раза за все время. Не обязательно аппендить все по каждому чиху.

READ ALSO
C# Windows form. CheckBox [закрыт]

C# Windows form. CheckBox [закрыт]

Как сделать, чтобы если один чекбокс активен, при нажатии на другой выбирался этот чекбокс, а с прежнего галочка удалялась?

122
Как создать нумерованный список в Microsoft Word c#?

Как создать нумерованный список в Microsoft Word c#?

Нужно создать нумерованный список в Word, например:

122
Тип DataRepeater существует в двух библиотеках

Тип DataRepeater существует в двух библиотеках

Столкнулся с проблемой, что Тип DataRepeater существует в двух библиотеках, но по сути это одна

89
Индекс выходить за границы массивы С#

Индекс выходить за границы массивы С#

Пишу программу, которая переводит число из одной системы счисления в другую, в самом конце программы, когда нужно выводить результат, вылетает...

107