পাইথনে বড় বড় ফাইলের MD5 হ্যাশ পান


188

আমি হ্যাশলিব ব্যবহার করেছি (যা পাইথন ২.6 / 3.0.০ তে এমডি 5 প্রতিস্থাপন করে) এবং যদি আমি একটি ফাইল খুলি এবং এর বিষয়বস্তুটি hashlib.md5()ফাংশনে রাখি তবে এটি দুর্দান্ত কাজ করেছে ।

সমস্যাটি খুব বড় ফাইলগুলির সাথে রয়েছে যেগুলির আকারগুলি র‌্যাম আকারের চেয়ে বেশি হতে পারে।

পুরো ফাইলটিকে মেমরিতে লোড না করে কোনও ফাইলের MD5 হ্যাশ পাবেন কীভাবে?


20
আমি পুনঃব্যবহার করব: "পুরো ফাইলটিকে মেমরিতে লোড না করে এমডি 5 এর একটি ফাইল কীভাবে পাবেন?"
এক্সটিএল

উত্তর:


147

8192-বাইট খণ্ডগুলিতে ফাইলটি ভাঙ্গুন (বা 128 বাইটের অন্য কোনও একাধিক) এবং একটানা ব্যবহার করে তাদের MD5 এ খাওয়ান update()

এটি এমডি 5 এর 128-বাইট ডাইজেস্ট ব্লক (8192 128 × 64 হয়) এর সুবিধা গ্রহণ করে। যেহেতু আপনি পুরো ফাইলটি মেমোরিতে পড়ছেন না, এটি 8192 বাইটের মেমরির বেশি ব্যবহার করবে না।

পাইথন 3.8+ এ আপনি করতে পারেন

import hashlib
with open("your_filename.txt", "rb") as f:
    file_hash = hashlib.md5()
    while chunk := f.read(8192):
        file_hash.update(chunk)
print(file_hash.digest())
print(file_hash.hexdigest())  # to get a printable str instead of bytes

81
আপনি 128 (8192, 32768 ইত্যাদি বলুন) এর কোনও একাধিকের ব্লক আকার কার্যকরভাবে কার্যকরভাবে ব্যবহার করতে পারেন এবং এটি একবারে 128 বাইট পড়ার চেয়ে আরও দ্রুত হবে।
jmanning2k

40
এই গুরুত্বপূর্ণ নোটটির জন্য jmanning2k ধন্যবাদ, 184MB ফাইলে একটি পরীক্ষা নেওয়া (0m9.230s, 0m2.547s, 0m2.429s) (128, 8192, 32768) ব্যবহার করে, আমি 8192 ব্যবহার করব কারণ উচ্চতর মান অ-লক্ষণীয় প্রভাব দেয়।
JustRegisterMe

যদি আপনি পারেন তবে আপনার hashlib.blake2bপরিবর্তে ব্যবহার করা উচিত md5। এমডি 5 এর বিপরীতে, BLAKE2 সুরক্ষিত এবং এটি আরও দ্রুত।
বরিস

2
@ বোরিস, আপনি আসলে বলতে পারবেন না যে BLAKE2 সুরক্ষিত। আপনি কেবলমাত্র এটিই বলতে পারেন যে এটি এখনও ভাঙ্গা হয়নি।
vy32

@ v3232 আপনি এটি বলতে পারবেন না এটি অবশ্যই ভেঙে যাবে। আমরা 100 বছরে দেখতে পাব, তবে এটি এমডি 5 এর চেয়ে কমপক্ষে ভাল যা অবশ্যই নিরাপদ।
বরিস

220

আপনার উপযুক্ত আকারের অংশগুলি ফাইল পড়তে হবে:

def md5_for_file(f, block_size=2**20):
    md5 = hashlib.md5()
    while True:
        data = f.read(block_size)
        if not data:
            break
        md5.update(data)
    return md5.digest()

দ্রষ্টব্য: নিশ্চিত হয়ে নিন যে আপনি 'rb' দিয়ে আপনার ফাইলটি খোলার জন্য খোলে - অন্যথায় আপনি ভুল ফলাফল পাবেন।

সুতরাং সম্পূর্ণ পদ্ধতিতে একটি পদ্ধতিতে - এমন কিছু ব্যবহার করুন:

def generate_file_md5(rootdir, filename, blocksize=2**20):
    m = hashlib.md5()
    with open( os.path.join(rootdir, filename) , "rb" ) as f:
        while True:
            buf = f.read(blocksize)
            if not buf:
                break
            m.update( buf )
    return m.hexdigest()

উপরের আপডেটটি ফ্রেরিচ রাবাবের দেওয়া মন্তব্যের ভিত্তিতে ছিল - এবং আমি এটি পরীক্ষা করেছি এবং এটি পাইথন ২.7.২ উইন্ডোজ ইনস্টলেশনতে সঠিক বলে মনে করেছি

আমি জ্যাকসাম সরঞ্জামটি ব্যবহার করে ফলাফলগুলি ক্রস-চেক করেছি।

jacksum -a md5 <filename>

http://www.jonelo.de/java/jacksum/


29
গুরুত্বপূর্ণ বিষয়টি যা গুরুত্বপূর্ণ তা হ'ল এই ফাংশনে পাস করা ফাইলটি বাইনারি মোডে খুলতে হবে, অর্থাৎ ফাংশনে যাওয়ার rbমাধ্যমে open
ফ্রেরিচ রাবাবে

11
এটি একটি সহজ সংযোজন, তবে এর hexdigestপরিবর্তে ব্যবহার digestকরলে একটি হেক্সাডেসিমাল হ্যাশ তৈরি হবে যা হ্যাশের বেশিরভাগ উদাহরণের মতো "দেখায়"।
tchaymore

এটা করা উচিত নয় if len(data) < block_size: break?
এরিক কাপলুন

2
এরিক, না, কেন হবে? ফাইলটি শেষ না হওয়া অবধি MD5 এ সমস্ত বাইট ফিড করা। আংশিক ব্লক পাওয়ার অর্থ এই নয় যে সমস্ত বাইট চেকসামে খাওয়ানো উচিত নয়।

2
@ ব্যবহারকারী 2084795 open সর্বদা ফাইলের শুরুতে অবস্থিত পজিশনের সাথে একটি নতুন ফাইল হ্যান্ডেল খোলে, (যদি আপনি
স্টিভ বার্নস

110

নীচে আমি মন্তব্য থেকে পরামর্শ অন্তর্ভুক্ত করেছি। আপনাকে ধন্যবাদ!

অজগর <3.7

import hashlib

def checksum(filename, hash_factory=hashlib.md5, chunk_num_blocks=128):
    h = hash_factory()
    with open(filename,'rb') as f: 
        for chunk in iter(lambda: f.read(chunk_num_blocks*h.block_size), b''): 
            h.update(chunk)
    return h.digest()

অজগর 3.8 এবং উপরে

import hashlib

def checksum(filename, hash_factory=hashlib.md5, chunk_num_blocks=128):
    h = hash_factory()
    with open(filename,'rb') as f: 
        while chunk := f.read(chunk_num_blocks*h.block_size): 
            h.update(chunk)
    return h.digest()

মূল পোস্ট

যদি আপনি ফাইলটি পড়ার আরও অজগর (কোন সত্যের সময় নয়) সম্পর্কে চিন্তা করেন তবে এই কোডটি পরীক্ষা করুন:

import hashlib

def checksum_md5(filename):
    md5 = hashlib.md5()
    with open(filename,'rb') as f: 
        for chunk in iter(lambda: f.read(8192), b''): 
            md5.update(chunk)
    return md5.digest()

নোট করুন যে ইটার () ফানকের ইওএফ-এ থামার জন্য প্রত্যাবর্তিত পুনরাবৃত্তির জন্য খালি বাইট স্ট্রিং দরকার, যেহেতু পড়ুন () রিটার্ন বি '' (কেবল '' নয়)।


17
আরও ভাল, 128*md5.block_sizeপরিবর্তে এর মতো কিছু ব্যবহার করুন 8192
mrkj

1
এমআরকেজে: আমি মনে করি আপনার ডিস্কের উপর ভিত্তি করে আপনার পঠন ব্লকের আকার বাছাই করা আরও গুরুত্বপূর্ণ এবং তারপরে এটি একাধিক নিশ্চিত করা md5.block_size
হার্ভে

6
b''সিনট্যাক্স আমার কাছে নতুন ছিল। এখানে ব্যাখ্যা করা হয়েছে
cod3monk3y

1
@ থারস্মোনার: আসলেই নয়, তবে ফ্ল্যাশ মেমরির জন্য আমার সর্বোত্তম ব্লকের আকারগুলি অনুসন্ধান করা থেকে, আমি কেবল 32k এর মতো একটি সংখ্যা বা 4, 8 বা 16 কে দিয়ে সহজেই বিভাজ্য কিছু বাছাইয়ের পরামর্শ দেব। উদাহরণস্বরূপ, যদি আপনার ব্লকের আকার 8k হয়, 32k পড়তে 4 টি সঠিক ব্লকের আকারে পড়তে হবে। যদি এটি 16 হয়, তবে ২. তবে প্রতিটি ক্ষেত্রেই আমরা ভাল কারণ আমরা একটি পূর্ণসংখ্যক ব্লক সংখ্যকটি পড়ব।
হার্ভে

1
"যখন ট্রু" বেশ পাইথোনিক।
জর্জেন এ। এয়ারহার্ড

49

এখানে আমার @Piotr Czapla এর পদ্ধতির সংস্করণটি রয়েছে:

def md5sum(filename):
    md5 = hashlib.md5()
    with open(filename, 'rb') as f:
        for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
            md5.update(chunk)
    return md5.hexdigest()

30

এই থ্রেডে একাধিক মন্তব্য / উত্তর ব্যবহার করা, এখানে আমার সমাধান:

import hashlib
def md5_for_file(path, block_size=256*128, hr=False):
    '''
    Block size directly depends on the block size of your filesystem
    to avoid performances issues
    Here I have blocks of 4096 octets (Default NTFS)
    '''
    md5 = hashlib.md5()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
             md5.update(chunk)
    if hr:
        return md5.hexdigest()
    return md5.digest()
  • এটি "পাইথোনিক"
  • এটি একটি ফাংশন
  • এটি অন্তর্নিহিত মানগুলি এড়ায়: সর্বদা স্বচ্ছ মানগুলি পছন্দ করে।
  • এটি (খুব গুরুত্বপূর্ণ) পারফরম্যান্স অপ্টিমাইজেশনের অনুমতি দেয়

এবং পরিশেষে,

- এটি একটি সম্প্রদায় দ্বারা নির্মিত হয়েছে, আপনার পরামর্শ / ধারণার জন্য সমস্ত ধন্যবাদ।


3
একটি পরামর্শ: আপনার এমডি 5 অবজেক্টটিকে বিকল্প হ্যাশিং ফাংশনগুলিতে মঞ্জুরি দেওয়ার জন্য ফাংশনের একটি toচ্ছিক প্যারামিটার তৈরি করুন, যেমন sha256 সহজেই MD5 প্রতিস্থাপন করতে পারে। আমি এটিকেও সম্পাদনা হিসাবে প্রস্তাব করব।
হক্কউইং

1
এছাড়াও: হজম মানব-পঠনযোগ্য নয়। হেক্সডিজাস্ট () আরও বোধগম্য, সাধারণত রিকগোনিজযোগ্য আউটপুট পাশাপাশি হ্যাশের সহজ বিনিময়ের অনুমতি দেয়
হক্কউইং

অন্য হ্যাশ ফর্ম্যাটগুলি প্রশ্নের আওতার বাইরে, তবে পরামর্শটি আরও জেনেরিক ফাংশনের জন্য প্রাসঙ্গিক। আপনার ২ য় পরামর্শ অনুসারে আমি একটি "মানব পাঠযোগ্য" বিকল্প যুক্ত করেছি।
বাসটিয়েন সেমিন

আপনি কীভাবে এখানে 'ঘন্টা' কাজ করছেন তা বিশদ দিয়ে বলতে পারেন?
এনিমিবাগ জোনস

@ এ্যানিবাগজোনস 'এইচআর' হ'ল মানব পাঠযোগ্য। এটি 32 চর দৈর্ঘ্যের হেক্সাডেসিমাল ডিজিটের একটি স্ট্রিং প্রদান করে: ডকস.পিথন.আর
এমডি

8

একটি পাইথন 2/3 পোর্টেবল সমাধান

একটি চেকসাম গণনা করতে (এমডি 5, শ 1, ইত্যাদি), আপনাকে অবশ্যই বাইনারি মোডে ফাইলটি খুলতে হবে, কারণ আপনি বাইটের মানগুলি যোগ করবেন:

Py27 / py3 পোর্টেবল হওয়ার জন্য আপনার ioপ্যাকেজগুলি ব্যবহার করা উচিত :

import hashlib
import io


def md5sum(src):
    md5 = hashlib.md5()
    with io.open(src, mode="rb") as fd:
        content = fd.read()
        md5.update(content)
    return md5

যদি আপনার ফাইলগুলি বড় হয়, আপনি মেমরির পুরো ফাইল সামগ্রী সংরক্ষণ করতে এড়াতে খণ্ডগুলি দ্বারা ফাইলটি পড়তে পছন্দ করতে পারেন:

def md5sum(src, length=io.DEFAULT_BUFFER_SIZE):
    md5 = hashlib.md5()
    with io.open(src, mode="rb") as fd:
        for chunk in iter(lambda: fd.read(length), b''):
            md5.update(chunk)
    return md5

এখানে কৌশলটি হ'ল সেন্ডিনেল (খালি স্ট্রিং) iter()দিয়ে ফাংশনটি ব্যবহার করা ।

এই ক্ষেত্রে তৈরি করা ইটারেটর তার পদ্ধতিতে প্রতিটি কলের জন্য কোনও যুক্তি ছাড়াই [ল্যাম্বডা ফাংশন] কল করবে next(); যদি ফেরত মানটি সেন্ডিনেলের সমান হয় StopIterationতবে উত্থাপিত হবে, অন্যথায় মানটি ফিরে আসবে।

যদি আপনার ফাইলগুলি সত্যিই বড় হয় তবে আপনার অগ্রগতির তথ্যও প্রদর্শন করতে হতে পারে। আপনি কলব্যাক ফাংশন কল করে এটি করতে পারেন যা গণনা করা বাইটের পরিমাণ মুদ্রণ করে বা লগ করে:

def md5sum(src, callback, length=io.DEFAULT_BUFFER_SIZE):
    calculated = 0
    md5 = hashlib.md5()
    with io.open(src, mode="rb") as fd:
        for chunk in iter(lambda: fd.read(length), b''):
            md5.update(chunk)
            calculated += len(chunk)
            callback(calculated)
    return md5

3

বাসটিয়েন সেমিন কোডের একটি রিমিক্স যা জেনেরিক হ্যাশিং ফাংশনটি সম্পর্কে হককিউং মন্তব্যকে বিবেচনা করবে ...

def hash_for_file(path, algorithm=hashlib.algorithms[0], block_size=256*128, human_readable=True):
    """
    Block size directly depends on the block size of your filesystem
    to avoid performances issues
    Here I have blocks of 4096 octets (Default NTFS)

    Linux Ext4 block size
    sudo tune2fs -l /dev/sda5 | grep -i 'block size'
    > Block size:               4096

    Input:
        path: a path
        algorithm: an algorithm in hashlib.algorithms
                   ATM: ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
        block_size: a multiple of 128 corresponding to the block size of your filesystem
        human_readable: switch between digest() or hexdigest() output, default hexdigest()
    Output:
        hash
    """
    if algorithm not in hashlib.algorithms:
        raise NameError('The algorithm "{algorithm}" you specified is '
                        'not a member of "hashlib.algorithms"'.format(algorithm=algorithm))

    hash_algo = hashlib.new(algorithm)  # According to hashlib documentation using new()
                                        # will be slower then calling using named
                                        # constructors, ex.: hashlib.md5()
    with open(path, 'rb') as f:
        for chunk in iter(lambda: f.read(block_size), b''):
             hash_algo.update(chunk)
    if human_readable:
        file_hash = hash_algo.hexdigest()
    else:
        file_hash = hash_algo.digest()
    return file_hash

0

আপনি সম্পূর্ণ সামগ্রী না পড়ে এটি এমডি 5 পেতে পারবেন না। তবে আপনি ব্লক করে ফাইল সামগ্রী ব্লক পড়তে আপডেট ফাংশনটি ব্যবহার করতে পারেন ।
m.update (ক); m.update (b) m.update (a + b) এর সমান


0

আমি মনে করি যে নিম্নলিখিত কোডটি আরও অজগর:

from hashlib import md5

def get_md5(fname):
    m = md5()
    with open(fname, 'rb') as fp:
        for chunk in fp:
            m.update(chunk)
    return m.hexdigest()

-1

জ্যাঙ্গোর জন্য গৃহীত উত্তরের প্রয়োগ:

import hashlib
from django.db import models


class MyModel(models.Model):
    file = models.FileField()  # any field based on django.core.files.File

    def get_hash(self):
        hash = hashlib.md5()
        for chunk in self.file.chunks(chunk_size=8192):
            hash.update(chunk)
        return hash.hexdigest()

-1

আমি লুপ পছন্দ করি না। @ নাথান ফেজারের উপর ভিত্তি করে:

md5 = hashlib.md5()
with open(filename, 'rb') as f:
    functools.reduce(lambda _, c: md5.update(c), iter(lambda: f.read(md5.block_size * 128), b''), None)
md5.hexdigest()

একাধিক ল্যাম্বডাস সমন্বিত ফান্টুলস.ড্রেস অ্যাবেশন সহ একটি সাধারণ এবং পরিষ্কার লুপটি প্রতিস্থাপনের কোন সম্ভাব্য কারণ আছে? আমি নিশ্চিত নই যে প্রোগ্রামিংয়ের কোনও সম্মেলন এটি ভেঙে গেছে কিনা।
নলথারিয়াল

আমার মূল সমস্যাটি হ'ল hashlibএসআইপিটি পাইথনের বাকী অংশগুলির সাথে সত্যই ভাল খেলতে পারে না। উদাহরণস্বরূপ আসুন আমরা shutil.copyfileobjনিবিড়ভাবে কাজ করতে ব্যর্থ হয় যা নেওয়া যাক । আমার পরবর্তী ধারণাটি ছিল fold(ওরফে reduce) যা একক বস্তুতে পুনরাবৃত্তিকে ভাঁজ করে। যেমন একটি হ্যাশ। hashlibঅপারেটরগুলি সরবরাহ করে না যা এটি কিছুটা জটিল করে তোলে। তবুও এখানে একটি পুনরাবৃত্তি ভাঁজ করা হয়েছিল।
সেবাস্তিয়ান ওয়াগনার

-3
import hashlib,re
opened = open('/home/parrot/pass.txt','r')
opened = open.readlines()
for i in opened:
    strip1 = i.strip('\n')
    hash_object = hashlib.md5(strip1.encode())
    hash2 = hash_object.hexdigest()
    print hash2

1
দয়া করে উত্তরে কোডটি ফর্ম্যাট করুন, এবং উত্তর দেওয়ার আগে এই বিভাগটি পড়ুন: ফ্যাক্সড
ফ্লোডাইফ

1
এটি সঠিকভাবে কাজ করবে না কারণ এটি পাঠ্য মোড লাইনে ফাইলটি লাইন দিয়ে পঠন করে এটির সাথে বিশৃঙ্খলা তৈরি করে এবং প্রতিটি স্ট্রিপ, এনকোডযুক্ত, লাইনটির এমডি 5 মুদ্রণ করছে!
স্টিভ বার্নেস 9

-4

আমি নিশ্চিত না যে এখানে খুব বেশি হৈচৈ পড়ছে না। আমার সম্প্রতি মাইএসকিউএল তে এমডি 5 এবং ফাইলগুলি ব্লব হিসাবে সঞ্চিত ফাইলগুলির সাথে সমস্যা হয়েছিল তাই আমি বিভিন্ন ফাইলের আকার এবং সোজা পাইথন পদ্ধতির সাথে পরীক্ষা করলাম, যেমন:

FileHash=hashlib.md5(FileData).hexdigest()

আমি 2Kb থেকে 20Mb ফাইলের আকারের সাথে কোনও পারফরম্যান্সের পার্থক্য সনাক্ত করতে পারি না এবং তাই হ্যাশিংয়ের 'খণ্ডন' করার দরকার নেই। যাইহোক, যদি লিনাক্সকে ডিস্কে যেতে হয় তবে সম্ভবত এটি এটির থেকে কম রাখার গড় প্রোগ্রামারের দক্ষতার পাশাপাশি এটিও করবে ability যেমনটি ঘটেছিল, সমস্যাটি এমডি 5 এর সাথে কিছুই করার ছিল না। আপনি যদি মাইএসকিউএল ব্যবহার করছেন তবে এমডি 5 () এবং শ 1 () ফাংশনটি ইতিমধ্যে ভুলে যাবেন না।


2
এটি প্রশ্নের উত্তর দিচ্ছে না এবং 20 এমবি খুব সম্ভবত একটি খুব বড় ফাইল হিসাবে বিবেচিত হবে যা এখানে আলোচিত হিসাবে র্যামের সাথে খাপ খায় না।
ক্রিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.