2010-08-23 5 views
10

У меня есть два текстовых файла 3GB, каждый файл имеет около 80 миллионов строк. И они имеют 99,9% идентичных строк (файл A имеет 60 000 уникальных строк, файл B содержит 80 000 уникальных строк).Быстро найти различия между двумя большими текстовыми файлами

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

Любые предложения приветствуются.

+0

ли вы имеете в виду, что 99,9% из * файлы * идентичны, или 99,9% * линии * идентичны (т. е. повторяется одна и та же линия)? – bstpierre

+0

Вам не нравится порядок линий? Имеет ли B все линии A в том же порядке, что и A? Может ли быть переупорядочение, удаление строк?Существуют ли повторяющиеся строки, количество которых имеет значение (A имеет n раз, B имеет n-b раз-> разность b * line) –

+1

Если вы спросите о «готовых инструментах командной строки», вы можете указать ОС. В большинстве случаев «diff» является либо родным, либо портированным. Тем не менее, я не могу быть уверен, что вы хотите от вашего вопроса: возможно, в Linux: sort --unique < file1 > uniq1; sort --unique < file2 > uniq1; diff uniq [12]. –

ответ

7

Если у вас есть вопросы, попробуйте утилиту comm. Если заказ не имеет значения, sort file1 file2 | uniq -u.

+0

Как будет сортироваться два файла 3G быстрее, чем 'diff'? – bstpierre

+1

@bstpierre: реализация 'diff' обычно квадратична, в то время как сортировка обычно является« n log n »в среднем случае (quicksort). – tonfa

2

С 60 000 или 80 000 уникальными строками вы можете просто создать словарь для каждой уникальной строки, сопоставляя его с числом. mydict["hello world"] => 1 и т. Д. Если ваша средняя строка составляет около 40-80 символов, это будет около 10 МБ памяти.

Затем прочитайте каждый файл, преобразуя его в массив чисел через словарь. Они будут легко вписываться в память (2 файла из 8 байтов * 3 ГБ/60 тыс. Строк меньше 1 МБ памяти). Затем разберите списки. Вы можете использовать invert the dictionary и использовать его для распечатки текста строк, которые отличаются.

EDIT:

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

#!/usr/bin/python 

class Reader: 

    def __init__(self, file): 
     self.count = 0 
     self.dict = {} 
     self.file = file 

    def readline(self): 
     line = self.file.readline() 
     if not line: 
      return None 
     if self.dict.has_key(line): 
      return self.dict[line] 
     else: 
      self.count = self.count + 1 
      self.dict[line] = self.count 
      return self.count 

if __name__ == '__main__': 
    print "Type Ctrl-D to quit." 
    import sys 
    r = Reader(sys.stdin) 
    result = 'ignore' 
    while result: 
     result = r.readline() 
     print result 
+0

@Harold L, я смущен. Как я могу сопоставить 60 000 или 80 000 уникальных строк в словаре, прежде чем узнать, какие строки содержатся в обоих файлах. – jack

+0

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

+0

dict.keys() с 3 ГБ? Я не верю, что вы можете сохранить хэш только с seff.dict [line], но он сохраняет всю строку в ключах + хэшах. –

1

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

uniqA = set(open('fileA', 'r')) 
3

Я думаю, что это самый быстрый способ (будь то в Python или другой язык, вопрос не должен иметь слишком много ИМО).

Примечание:

1.I только хранить хэш каждой строки, чтобы сэкономить место (и время, если может произойти пейджинг)

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

3. Я предполагаю, что хеш-функция не вызывает конфликтов. Это почти, но не совсем точно.

4.I import hashlib потому что встроенная функция hash() слишком короткая, чтобы избежать конфликтов.

import sys 
import hashlib 

file = [] 
lines = [] 
for i in range(2): 
    # open the files named in the command line 
    file.append(open(sys.argv[1+i], 'r')) 
    # stores the hash value and the line number for each line in file i 
    lines.append({}) 
    # assuming you like counting lines starting with 1 
    counter = 1 
    while 1: 
     # assuming default encoding is sufficient to handle the input file 
     line = file[i].readline().encode() 
     if not line: break 
     hashcode = hashlib.sha512(line).hexdigest() 
     lines[i][hashcode] = sys.argv[1+i]+': '+str(counter) 
     counter += 1 
unique0 = lines[0].keys() - lines[1].keys() 
unique1 = lines[1].keys() - lines[0].keys() 
result = [lines[0][x] for x in unique0] + [lines[1][x] for x in unique1] 
+1

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

+0

Да, очень хорошая точка. – max

0

Python имеет difflib, который утверждает, что вполне конкурентоспособен с другими дифф утилитами см: http://docs.python.org/library/difflib.html

+0

Может ли эта библиотека обрабатывать текстовые файлы 3gb ?! Даже хорошие базы данных имеют трудное время с такой задачей ... Им нужна индексация и другая оптимизация, чтобы получить результат в разумные сроки. – Asaf

+0

Поскольку строки находятся в случайном порядке, и нет необходимости находить изменения линий, возможно, не лучший подход. Было бы уместно, если два файла являются версиями одного и того же файла (была возможность из-за высокого сходства в строках между ними). –

Смежные вопросы