Return md5 hash value of a piece of a file
    
    Estimate processing time on:
    
    :param abspath: the absolute path to the file
    :param nbytes: only has first N bytes of the file. if 0, hash all file
    
    CPU = i7-4600U 2.10GHz - 2.70GHz, RAM = 8.00 GB
    1 second can process 0.25GB data
    
    - 0.59G - 2.43 sec
    - 1.3G - 5.68 sec
    - 1.9G - 7.72 sec
    - 2.5G - 10.32 sec
    - 3.9G - 16.0 sec
    
    ATTENTION:
        if you change the meta data (for example, the title, years 
        information in audio, video) of a multi-media file, then the hash 
        value gonna also change.

def md5file(abspath, nbytes=0):
    """Return md5 hash value of a piece of a file
    
    Estimate processing time on:
    
    :param abspath: the absolute path to the file
    :param nbytes: only has first N bytes of the file. if 0, hash all file
    
    CPU = i7-4600U 2.10GHz - 2.70GHz, RAM = 8.00 GB
    1 second can process 0.25GB data
    
    - 0.59G - 2.43 sec
    - 1.3G - 5.68 sec
    - 1.9G - 7.72 sec
    - 2.5G - 10.32 sec
    - 3.9G - 16.0 sec
    
    ATTENTION:
        if you change the meta data (for example, the title, years 
        information in audio, video) of a multi-media file, then the hash 
        value gonna also change.
    """    
    m = hashlib.md5()
    with open(abspath, "rb") as f:
        if nbytes:
            data = f.read(nbytes)
            if data:
                m.update(data)
        else:
            while True:
                data = f.read(1 << 20)
                if not data:
                    break
                m.update(data)
    return m.hexdigest()