ReadLine () против Read (), чтобы получить CR и LF эффективно? - PullRequest
5 голосов
/ 02 сентября 2011

Я работаю над программой на C #, чтобы определить длину строки для каждой строки в нескольких больших текстовых файлах с более чем 100 000 строк перед импортом с использованием пакета служб SSIS.Я также буду проверять другие значения в каждой строке, чтобы убедиться, что они правильные, прежде чем импортировать их в мою базу данных с помощью служб SSIS.

Например, я ожидаю, что длина строки 3000 символов, а затем CR на 3001 и LF на 3002, поэтому в целом 3002 символа.

При использовании ReadLine () он читаетCR или LF как и конец строки, так что я не могу проверить символы CR или LF.Я просто проверял длину линии на 3000, чтобы определить, была ли длина правильной.Я только что столкнулся с проблемой, когда файл имеет LF в позиции 3001, но отсутствует CR.Поэтому ReadLine () говорит, что это 3000 символов, которые являются правильными, но в моем пакете служб SSIS произойдет сбой, поскольку отсутствует CR.

Я проверил, что Read () будет достигать каждого символа 1 одновременно, и яЯ могу определить, есть ли в каждой строке CR и LF, но это кажется довольно непродуктивным, и когда у некоторых файлов, с которыми я столкнусь, будет более 5 000 000 строк, это будет очень неэффективно.Затем мне нужно будет добавить каждый символ в строку или использовать ReadBlock () и преобразовать массив символов в строку, чтобы я мог проверить другие значения в строке.

Есть ли у кого-нибудь какие-либо идеи относительно эффективногоспособ проверить линию на наличие CR и LF и других значений в данной строке, не тратя лишних ресурсов и закончить относительно своевременно.

Ответы [ 5 ]

4 голосов
/ 02 сентября 2011

проверил, что Read () будет достигать каждого символа 1 за раз, и я могу определить, есть ли у каждой строки CR и LF, но это кажется довольно непродуктивным

Подумай об этом. Как вы думаете, ReadLine() имеет волшебную палочку и не должен читать каждый символ?

Просто создайте свой собственный ReadMyLine (). Что-то должно читать символы, не имеет значения, это ваш код или библиотека. Ввод / вывод будет буферизован Stream и Windows.

1 голос
/ 02 сентября 2011

Я полагаю, вы найдете эту версию эффективной:

    static bool CheckFile(string filename)
    {
        const int BUFFER_SIZE = 3002;

        var Reader = new StreamReader(filename, Encoding.ASCII, false, BUFFER_SIZE);

        var buffer = new char[BUFFER_SIZE];

        int offset = 0;
        int bytesRead = 0;

        while((bytesRead = Reader.Read(buffer, offset, BUFFER_SIZE)) > 0)
        {
            if(bytesRead != BUFFER_SIZE 
                || buffer[BUFFER_SIZE - 2] != '\r' 
                || buffer[BUFFER_SIZE - 1] != '\n')
            {
                //the file does not conform
                return false;
            }

            offset += bytesRead;
        }

        return true;
    }

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

1 голос
/ 02 сентября 2011

Можете ли вы использовать переопределение StreamReader.Read ИЛИ переопределение TextReader.Read , которое принимает 3 параметра - строковый буфер (в вашем случае массив из 3002 символов), индекс startint(вы будете обрабатывать это в цикле каждый раз, увеличивая индекс на 3002), количество символов для чтения (3002).Из буфера чтения вы можете проверить последние два символа для вашей условной оценки CR и LF.

1 голос
/ 02 сентября 2011

Я могу что-то здесь упустить, но если данные в каждой строке всегда точно 3000 символов (исключая CR и LF)?

Почему бы просто не прочитать каждую строку, а затем взять только первые 3000 символов, используя string.Substring().Таким образом, вам не нужно беспокоиться о том, как именно завершается строка.

то есть

 using (StreamReader sr = new StreamReader("TestFile.txt")) 
    {
       String line;
       while ((line = sr.ReadLine()) != null) 
          {
            // string data = line.subString(0,3000); 
            // edit, if data is sometimes < 3000 ....  
            string data = line.subString(0,line.length < 3000 ? line.length : 3000);
            // do something with data
          }
     }
0 голосов
/ 02 сентября 2011

Думаю, я наконец-то понял код, чтобы получить именно то, что я хочу, мысли? Основная проблема, с которой я столкнулся, заключалась в том, что я не гарантирую, что длина моей линии будет исправлена. Другой мудрый метод, упомянутый @Paul Keister, сработал бы отлично, и сделал так, как я его проверил. Спасибо за помощь!

int asciiValue = 0;

while (asciiValue != -1)
{

Boolean endOfRow = false;
Boolean endOfRowValid = true;

string currentLine = "";

while (endOfRow == false)
{
    asciiValue = file.Read();

    if (asciiValue == 10 || asciiValue == 13)
    {
        int asciiValueTemp = file.Peek();

        if (asciiValue == 13 && asciiValueTemp == 10)
        {
            endOfRow = true;
            asciiValue = file.Read();
        }
        else
        {
            endOfRowValid = false;
            endOfRow = true;
        }
    }
    else if (asciiValue != -1)
        currentLine += char.ConvertFromUtf32(asciiValue);
    else
        endOfRow = true;
}

Редактировать: я забыл упомянуть, что это кажется таким же эффективным, как использование ReadLine (). Я действительно боялся, что это не сработало бы. Похоже, я был неправ.

...