Разбор текстового файла в C # с пропуском некоторого содержимого - PullRequest
1 голос
/ 06 мая 2009

Я пытаюсь разобрать текстовый файл с заголовком и телом. В заголовке этого файла есть ссылки на номера строк в разделах тела. Например:

SECTION_A 256
SECTION_B 344
SECTION_C 556

Это означает, что SECTION_A начинается в строке 256.

Что было бы лучшим способом разобрать этот заголовок в словаре, а затем при необходимости прочитать разделы.

Типичные сценарии:

  1. Разбор заголовка и раздел только для чтения SECTION_B
  2. Разобрать заголовок и прочитать первый абзац каждого раздела.

Файл данных довольно большой, и я определенно не хочу загружать все это в память и затем работать с ним.

Буду признателен за ваши предложения. Моя среда VS 2008 и C # 3.5 SP1.

Ответы [ 5 ]

3 голосов
/ 06 мая 2009

Вы можете сделать это довольно легко.

Проблема состоит из трех частей.

1) Как найти, где начинается строка в файле. Единственный способ сделать это - прочитать строки из файла, сохранив список, в котором записана начальная позиция в файле этой строки. * например 1005 *

List lineMap = new List();
lineMap.Add(0);    // Line 0 starts at location 0 in the data file (just a dummy entry)
lineMap.Add(0);    // Line 1 starts at location 0 in the data file

using (StreamReader sr = new StreamReader("DataFile.txt")) 
{
    String line;
    int lineNumber = 1;
    while ((line = sr.ReadLine()) != null)
        lineMap.Add(sr.BaseStream.Position);
}

2) Прочитайте и проанализируйте ваш индексный файл в словаре.

Dictionary index = new Dictionary();

using (StreamReader sr = new StreamReader("IndexFile.txt")) 
{
    String line;
    while ((line = sr.ReadLine()) != null)
    {
        string[] parts = line.Split(' ');  // Break the line into the name & line number
        index.Add(parts[0], Convert.ToInt32(parts[1]));
    }
}

Затем, чтобы найти строку в вашем файле, используйте:

int lineNumber = index["SECTION_B";];         // Convert section name into the line number
long offsetInDataFile = lineMap[lineNumber];  // Convert line number into file offset

Затем откройте новый FileStream в DataFile.txt, Seek (offsetInDataFile, SeekOrigin.Begin), чтобы перейти к началу строки, и используйте StreamReader (как указано выше), чтобы прочитать строки из него.

2 голосов
/ 06 мая 2009

Ну, очевидно, вы можете сохранить имя + номер строки в словаре, но это не принесет вам пользы.

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

Лучшим способом было бы написать оболочку, которая декодирует текстовое содержимое (если у вас есть проблемы с кодировкой) и может дать вам номер строки для типа отображения байтовой позиции, тогда вы можете взять этот номер строки 256 и посмотреть в словаре, чтобы узнать, что строка 256 начинается с позиции 10000 в файле, и начать чтение оттуда.

Это одноразовая обработка? Если нет, то рассматривали ли вы возможность помещения всего файла в локальную базу данных, например, в базу данных SQLite? Это позволит вам иметь прямое отображение между номером строки и ее содержимым. Конечно, этот файл будет даже больше, чем ваш исходный файл, и вам нужно будет скопировать данные из текстового файла в базу данных, так что в любом случае есть некоторые издержки.

0 голосов
/ 06 мая 2009

Вы можете читать построчно, пока вся информация о заголовке не будет захвачена и остановлена ​​(при условии, что все указатели разделов находятся в заголовке). У вас будут номера разделов и строк для использования при извлечении данных позднее.

string dataRow = "";

try
{
    TextReader tr = new StreamReader("filename.txt");

    while (true)
    {
        dataRow = tr.ReadLine();
        if (dataRow.Substring(1, 8) != "SECTION_")
            break;
        else
            //Parse line for section code and line number and log values
            continue;
    }
    tr.Close();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}
0 голосов
/ 06 мая 2009

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

Dictionary<string, int> sectionIndex = new Dictionary<string, int>();
List<string> headers = new List<string>(); // fill these with readline

foreach(string header in headers) {
    var s = header.Split(new[]{' '});
    sectionIndex.Add(s[0], Int32.Parse(s[1]));
}

Найдите нужную вам словарную запись, ведите счетчик количества строк, прочитанных в файле, и выполняйте циклы, пока не достигнете этого номера строки, затем читайте, пока не достигнете начальной строки следующего раздела. Я не знаю, можете ли вы гарантировать порядок ключей в Словаре, поэтому вам, вероятно, понадобятся имена текущего и следующего разделов.

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

0 голосов
/ 06 мая 2009

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

...