Как читать два больших файла и сравнивать содержимое - PullRequest
0 голосов
/ 26 августа 2018

То, что я пытаюсь сделать, это прочитать большой файл 5.6ГБ имеет примерно 600 миллионов строк, а второй 16МБ имеет 2M строк.

Я хочу проверить дубликаты строк в этих двух файлах.

$wordlist = array_unique(array_filter(file('small.txt', FILE_IGNORE_NEW_LINES)));
$duplicate = array();
if($file = fopen('big.txt', 'r')){
    while(!feof($file)){
        $lines = rtrim(fgets($file));
        if(in_array($lines, $wordlist)){
            echo $lines." : exists.\n";
        }
    }
    fclose($file);
}

Но это займет вечность, чтобы закончить (он работал с 6 часов и еще не закончил: /).

Мой вопрос.Есть ли лучший способ быстрого поиска в огромных файлах?

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Вам не нужно будет вызывать array_filter() или array_unique(), если вы собираетесь позвонить array_flip() - это исключит дубликаты для вас, потому что вы не можете иметь дубликаты ключей на одном уровне массива .

Кроме того:

  1. array_unique() указано медленнее, чем array_flip() (и бывают случаи, когда оно медленнее, чем два array_flip() с)
  2. array_filter() имеет плохую репутацию для уничтожения данных Falsey / empty / null / zero-ish, поэтому я предостерегаю вас не использовать его поведение по умолчанию.
  3. array_flip() устанавливает очень быструю проверку isset(). isset(), вероятно, будет превосходить array_key_exists(), потому что isset() не проверяет значения null.
  4. Я добавляю флаг FILE_SKIP_EMPTY_LINES к вызову file(), чтобы ваш массив поиска был потенциально меньше.
  5. Вызов rtrim() каждой строки вашего большого файла может также вызывать некоторое перетаскивание. Знаете ли вы, если у вас есть одинаковые символы новой строки в обоих файлах? Если бы вы могли безопасно удалить флаг FILE_IGNORE_NEW_LINES из вызова file(), вы бы сэкономили шестьсот миллионов вызовов rtrim(). В качестве альтернативы, если вы знаете символы новой строки (например, \n? Или \r\n?), Которые следуют за строками big.txt, вы можете добавить конкретные символы новой строки к клавишам $lookup - это означает подготовку данных меньшего файла к каждой строке большого файла.

непроверенный код:

$lookup = array_flip(file('small.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
if($file = fopen('big.txt', 'r')){
    while(!feof($file)){
        $line = rtrim(fgets($file));
        if (isset($lookup[$line])) {
            echo "$lines : exists.\n";
        }
    }
    fclose($file);
}
0 голосов
/ 26 августа 2018

Я думаю,

 $wordlist=array_flip(array_unique(array_filter(file('small.txt', FILE_IGNORE_NEW_LINES))));

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

if($file1 = fopen('big.txt', 'r')){
    if($file = fopen('small.txt', 'r')){
        while(!feof($file)){
            $line=trim(fgets($file));
            if(!isset($wordlist[$line])&&!ctype_space($line)&&!empty($line)){
                $wordlist[$line]=0;
            }
        }
        fclose($file); 
    }
    while(!feof($file1)){
        $line1 = trim(fgets($file1));
        if(isset($wordlist[$line1]))
            $wordlist[$line1]++;            
    }
  fclose($file1); 
}

На этом шагепеременная $ wordlist содержит список всех строк в вашем файле small.txt и количество вхождений каждой строки в вашем файле big.txt.Вы можете использовать этот массив или отфильтровать его, чтобы удалить пустые строки. Вы также можете отсортировать массив с помощью uasort, чтобы узнать больше о том, какие строки встречаются чаще, а какие - меньше, и вы даже можете пойти дальше в своем анализе ...

...