#.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), который можно было бы адаптировать, чтобы он стал основой потокового решения проблемы.