Use default hash method to return hash value of a piece of a file

        Estimate processing time on:

        :type abspath: text_type
        :param abspath: the absolute path to the file.

        :type nbytes: int
        :param nbytes: only has first N bytes of the file. if 0, hash all file.

        :type chunk_size: int
        :param chunk_size: The max memory we use at one time. 

        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 of_file(self, abspath, nbytes=0, chunk_size=1024):
        """
        Use default hash method to return hash value of a piece of a file

        Estimate processing time on:

        :type abspath: text_type
        :param abspath: the absolute path to the file.

        :type nbytes: int
        :param nbytes: only has first N bytes of the file. if 0, hash all file.

        :type chunk_size: int
        :param chunk_size: The max memory we use at one time. 

        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.
        """
        if nbytes < 0:
            raise ValueError("chunk_size cannot smaller than 0")
        if chunk_size < 1:
            raise ValueError("chunk_size cannot smaller than 1")
        if (nbytes > 0) and (nbytes < chunk_size):
            chunk_size = nbytes

        m = self.hash_algo()
        with open(abspath, "rb") as f:
            if nbytes:  # use first n bytes
                have_reads = 0
                while True:
                    have_reads += chunk_size
                    if have_reads > nbytes:
                        n = nbytes - (have_reads - chunk_size)
                        if n:
                            data = f.read(n)
                            m.update(data)
                        break
                    else:
                        data = f.read(chunk_size)
                        m.update(data)
            else:  # use entire content
                while True:
                    data = f.read(chunk_size)
                    if not data:
                        break
                    m.update(data)

        return m.hexdigest()