Как Вы ищете файл крупного текста строку, не идя линию за линией в C#?

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

Этот метод является чрезвычайно медленным из-за размера файлов (больше чем 100 МБ).

13
задан Peter Mortensen 28 June 2015 в 21:23
поделиться

12 ответов

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

Очевидно, если часть найденна строки находится в конце файла, не будет прироста производительности.

0
ответ дан 1 December 2019 в 22:57
поделиться

Прикрепите его на SQL Server 2005/2008 и используйте его полнотекстовые поисковые возможности.

0
ответ дан 1 December 2019 в 22:57
поделиться

Если вы ищете только определенную строку, я бы сказал, что Line-By-Line является лучшим и наиболее эффективным механизмом. С другой стороны, если вы собираетесь искать несколько строк, особенно в нескольких разных точках в приложении, вы можете посмотреть Lucene.net , чтобы создать индекс, а затем запрашивать индекс Отказ Если это один выключенный (т. Е. Вам не нужно будет запрашивать один и тот же файл позже), вы можете создать индекс во временном файле, который будет автоматически очищен системой (обычно время загрузки; или вы Можно удалить его сами, когда ваша программа выходит). Если вам нужно снова искать тот же файл позже, вы можете сохранить индекс в известном месте и получить гораздо лучшую производительность во второй раз.

0
ответ дан 1 December 2019 в 22:57
поделиться

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

единственный способ избежать поиска по всему файлу - это отсортировать или организовать ввод заранее. Например, если это файл XML, и вам нужно сделать много из этих поисков, это имеет смысл для анализа файла XML в дереве DOM. Или если это список слов, и вы ищете все слова, начинающиеся с букв «Aero», это может иметь смысл сортировать весь вход первый в первую очередь, если вы будете делать много такого поиска в одном файле Отказ

0
ответ дан 1 December 2019 в 22:57
поделиться

Помните, что

log(n!) = log(1) + log(2) + ... + log(n-1) + log(n)

Вы можете получить верхнюю границу от

log(1) + log(2) + ... + log(n) <= log(n) + log(n) + ... + log(n)
                                = n*log(n)

И вы можете получить нижнюю границу, сделав то же самое после выбрасывания первой половины суммы:

log(1) + ... + log(n/2) + ... + log(n) >= log(n/2) + ... + log(n) 
                                       = log(n/2) + log(n/2+1) + ... + log(n-1) + log(n)
                                       >= log(n/2) + ... + log(n/2)
                                        = n/2 * log(n/2) 
-121--619191-

Я не уверен, что вы надеетесь извлечь из этого, но так как у меня есть это передо мной... win32 IBM 1,4,2 JRE использует размер буфера 2048 .

-121--1691005-

Если требуется ускорить построчное чтение, можно создать приложение на основе очереди:
Один поток считывает строки и передает их в очередь threadsafe. Второй может затем обработать последовательности

0
ответ дан 1 December 2019 в 22:57
поделиться

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

Это будет влиять на уменьшение количества чтения на файл и, вероятно, будет более быстрый метод, но оно будет более из памяти, если вы установите размер буфера слишком высоким.

1
ответ дан 1 December 2019 в 22:57
поделиться

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

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

Чтобы индексировать файл для поиска полного текста, вы можете использовать библиотеку Lucene.net.

http://incubator.apache.org/lucene.net/

1
ответ дан 1 December 2019 в 22:57
поделиться

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

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

-121--2695398-

Хотя я не знаю API iPhone, я знаю что-то о GPS и инерциальной навигации. Это может быть полезно.

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

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

В любом случае, просто некоторые вещи, о которых нужно подумать.

-121--2779512-

Вы должны иметь возможность читать символ файла по символу, соответствующему каждому символу в последовательности поиска, пока не достигнете конца последовательности поиска, и в этом случае у вас есть совпадение. Если в какой-либо пункт прочитанный символ не соответствует искомому символу, сбросьте соответствующий счетчик на 0 и начните заново. Например (* * * * псевдокод/не протестирован * * * *):

byte[] lookingFor = System.Text.Encoding.UTF8.GetBytes("hello world");
int index = 0;
int position = 0;
bool matchFound = false;

using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
{
  while (fileStream.ReadByte() == lookingFor[index])
  {
    index++;

    if (index == lookingFor.length) 
    {
       matchFound = true;
       position = File.position - lookingFor.length;
       break;
    }
  }
}

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

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

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

1
ответ дан 1 December 2019 в 22:57
поделиться

Самый быстрый метод поиска - это алгоритм Бойера-Мура . Этот метод не требует прочетки всех байтов из файлов, но требует случайного доступа к байтам. Кроме того, этот метод прост в реализации.

2
ответ дан 1 December 2019 в 22:57
поделиться

Во всех случаях вам придется пройти весь файл.

Просмотр Стройный поиск Rabin-Karp или аналогичный.

2
ответ дан 1 December 2019 в 22:57
поделиться

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

7
ответ дан 1 December 2019 в 22:57
поделиться

Вот мое решение, которое использует поток для чтения одного символа за раз. Я создал пользовательский класс для поиска значения одного символа за раз, пока все значение не найдено.

Я провел некоторые тесты с файлом 100 МБ, сохраненным на сетевом диске, а скорость была полностью зависимой от того, как быстро она может прочитать в файле. Если файл был забуферен в Windows, поиск всего файла занял менее 3 секунд. В противном случае это может занять от 7 секунд до 60 секунд, в зависимости от скорости сети.

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

public static int FindInFile(string fileName, string value)
{   // returns complement of number of characters in file if not found
    // else returns index where value found
    int index = 0;
    using (System.IO.StreamReader reader = new System.IO.StreamReader(fileName))
    {
        if (String.IsNullOrEmpty(value))
            return 0;
        StringSearch valueSearch = new StringSearch(value);
        int readChar;
        while ((readChar = reader.Read()) >= 0)
        {
            ++index;
            if (valueSearch.Found(readChar))
                return index - value.Length;
        }
    }
    return ~index;
}
public class StringSearch
{   // Call Found one character at a time until string found
    private readonly string value;
    private readonly List<int> indexList = new List<int>();
    public StringSearch(string value)
    {
        this.value = value;
    }
    public bool Found(int nextChar)
    {
        for (int index = 0; index < indexList.Count; )
        {
            int valueIndex = indexList[index];
            if (value[valueIndex] == nextChar)
            {
                ++valueIndex;
                if (valueIndex == value.Length)
                {
                    indexList[index] = indexList[indexList.Count - 1];
                    indexList.RemoveAt(indexList.Count - 1);
                    return true;
                }
                else
                {
                    indexList[index] = valueIndex;
                    ++index;
                }
            }
            else
            {   // next char does not match
                indexList[index] = indexList[indexList.Count - 1];
                indexList.RemoveAt(indexList.Count - 1);
            }
        }
        if (value[0] == nextChar)
        {
            if (value.Length == 1)
                return true;
            indexList.Add(1);
        }
        return false;
    }
    public void Reset()
    {
        indexList.Clear();
    }
}
4
ответ дан 1 December 2019 в 22:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: