Как получить все индексы строк в большом файле?

#.net #vb.net #file-io

#.net #vb.net #file-io

Вопрос:

Представьте, что есть очень большой HTML-файл с, конечно, большим количеством html-тегов. Я не могу загрузить весь файл в память.

Я намерен извлечь все индексы для этой <p> и этой </p> строк. Как я должен этого добиться? Пожалуйста, предложите мне несколько указаний, как это сделать.

Комментарии:

1. насколько большой? как, скажем, гигабайтный Html-файл? откуда вы берете такой HTML-код?

2. @Simon Mourier: Это не имеет значения. Я приветствую ваш ответ.

Ответ №1:

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

Ответ №2:

Пример с использованием файловых потоков:

 /// <summary>
/// Get a collection of index,string for everything inside p tags in the html file
/// </summary>
/// <param name="htmlFilename">filename of the html file</param>
/// <returns>collection of index,string</returns>
private Dictionary<long, string> GetHtmlIndexes(string htmlFilename)
{
    //init result
    Dictionary<long, string> result = new Dictionary<long, string>();

    StreamReader sr = null;
    try
    {
        sr = new StreamReader(htmlFilename);
        long offsetIndex = 0;
        while (!sr.EndOfStream)
        {

            string line = sr.ReadLine(); //assuming html isn't condensed into 1 single line
            offsetIndex  = line.Length;  //assuming 'index' you require is the file offset
            int openingIndex = line.IndexOf(@"<p");
            int closingIndex = line.IndexOf(@">");
            if ( openingIndex > -1)
            {
                int contentIndex = openingIndex   3; // as in <p tag or <p>tag
                string pTagContent = line.Substring( contentIndex);
                if(closingIndex> contentIndex)
                {
                    int tagLength = closingIndex - contentIndex;
                    pTagContent = line.Substring( contentIndex, tagLength);
                }
                //else, the tag finishes on next or subsequent lines and we only get content from this line

                result.Add(offsetIndex   contentIndex, pTagContent);
            }


        } //end file loop

    }
    catch (Exception ex)
    {
        //handle error ex
    }
    finally
    {
        if(sr!=null)
            sr.Close();
    }


    return resu<
}
  

Это имеет ограничения, которые вы можете видеть из комментариев.
Я подозреваю, что использование LINQ будет намного аккуратнее. Я надеюсь, это даст вам отправную точку?

Комментарии:

1. Похоже, что он также будет соответствовать тегу <param> или <pre> , и я не вижу никакой логики для закрывающего </p> тега?

Ответ №3:

Вам следует попробовать Html Agility Pack.

Комментарии:

1. Пакет Html Agility Pack — это фантастика, но я видел, как он прогибается под большими блоками HTML. Я полагаю, что у OP будут проблемы с разбором «больших файлов». Но это определенно стоит изучить.

Ответ №4:

Если ваш HTML — это чистый XHTML, то вы могли бы рассматривать его как XML-документ. Загрузите ваш XHTML в System.Xml.XmlDocument , а затем используйте GetElementsByTagName("p") метод для возврата списка <p>-тегов. Это намного безопаснее и проще, чем пытаться анализировать HTML напрямую.

Ответ №5:

Я бы начал с создания HTML-токенизатора, использование которого IEnumerable , yield return и т.д. было бы простым. Он мог бы читать файл по символам, используя StreamReader.Read а конечный автомат switch определял бы текущее состояние и выдавал последовательность токенов или Tuple ов.

Здесь я нашел старый HTML-токенизатор (часть старого движка блогов Криса Андерсона BlogX), который можно было бы адаптировать, чтобы он стал основой потокового решения проблемы.