2016-12-27 4 views
1

Изменено ВопросВычислить md5 на лету при чтении большого текстового файла

Я знаю, как использовать Python для создания MD5 хэш из файла http://docs.python.org/3.5/library/hashlib.html#hash-algorithms. Я также знаю, как читать текстовый файл по строкам. Однако мои файлы могут расти большими, и это неэффективно, чтобы прочитать файл дважды от начала до конца. Интересно, можно ли читать данные только один раз с диска, и, как в потоке/трубе, объединить 2 задачи разумно. Может быть что-то вроде:

  1. Инициализировать MD5
  2. открыть файл в двоичном режиме
  3. читать порцию данных (например, buffer_size = 65536) в буфер
  4. Обновлять md5 с куском просто читать
  5. обеспечивает буфер в другой поток, чтобы продолжить обработку данных
  6. использование TextIOWrapper (?), чтобы снова прочитать данные, но на этот раз это текст
  7. чтения текст за строкой. Когда буфер потребляется, задайте базовый уровень для получения дополнительных данных, пока EOF. Он будет читать больше двоичных данных, обновлять md5, предоставлять новый буфер ... и я могу продолжить чтение строки за строкой (это похоже: повторите с шага 3 до EOF)
  8. после EOF, я обработал все мои текстовая строка за строкой, и имеют md5

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

Надеюсь, это объяснит это лучше. В очередной раз благодарим за помощь.

Юрген

+0

Эта страница Я знаю, и я читал его раньше. Но где именно он описывает, что я хочу использовать тот самый буфер, который я прочитал для md5, для чтения текста по строкам? – Juergen

+0

Посмотрите, моя проблема не в md5.Моя проблема: a) читать буферы из двоичного файла; b) делать что-то с буфером; c) использовать этот буфер (который не является байтом) для чтения текста там по строкам. У вас нет рабочего примера случайно? – Juergen

ответ

1

Да, просто создать один hashlib.md5() object и обновлять его с каждым блоком:

md5sum = hashlib.md5() 

buffer_size = 2048 # 2kb, adjust as needed. 

with open(..., 'rb') as fileobj: 
    # read a binary file in chunks 
    for chunk in iter(lambda: fileobj.read(buffer_size), b''): 
     # update the hash object 
     md5sum.update(chunk) 

# produce the final hash digest in hex. 
print(md5sum.hexdigest()) 

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

  • либо один, который реализует TextIOBase API (реализовать все stub methods, которые относятся к чтению), и втягивать данные из BufferedIOReader объект, созданный по вызову open(..., 'rb'), каждый раз, когда запрашивается строка. В этот момент вам придется выполнять собственное разделение и декодирование строк.

  • или тот, который реализует BufferedIOBase API (снова реализуйте все методы заглушки) и передайте это как буфер на TextIOWrapper class.

+0

Это точно моя проблема. Я знаю, как создать хеш-файл md5. Но я борюсь с деталями TextIOBase, BufferedOOBase и TextIOWrapper. У вас нет примера случайно? – Juergen

+1

@Juergen: не могли бы вы поделиться своими попытками в вопросе? Гораздо легче помочь исправить ошибки, чем написать что-то с нуля. Сегодня у меня мало времени, может быть, я не смогу смотреть до завтра. –

1

Это похоже на работу в Python 3.6

#!/usr/bin/env python 

import io 
import hashlib 

class MD5Pipe(io.BytesIO): 
    def __init__(self, fd): 
     self.fd = fd 
     self.hasher = hashlib.md5() 
    def readinto(self, b): 
     l = self.fd.readinto(b) 
     # print("readinto: ", l, len(b)) 
     if l > 0: 
      self.hasher.update(b[0:l]) 
     return l 
    def hexdigest(self): 
     return self.hasher.hexdigest() 

blocksize = 65536 
file = "c:/temp/PIL/VTS/VTS_123.csv" 
with open(file, "rb") as fd: 
    with MD5Pipe(fd) as md5: 
     with io.BufferedReader(md5) as br: 
      with io.TextIOWrapper(br, newline='', encoding="utf-8") as reader: 
       for line in reader: 
        print("line: ", line, end="") 

       print("md5: ", md5.hexdigest())