'Read at most `size` bytes from the file (less if there
isn\'t enough data).
The bytes are returned as an instance of :class:`str` (:class:`bytes`
in python 3). If `size` is negative or omitted all data is read.
:Parameters:
- `size` (optional): the number of bytes to read'

def read(self, size=(-1)):

    self._ensure_file()
    if (size == 0):
        return EMPTY
    remainder = (int(self.length) - self.__position)
    if ((size < 0) or (size > remainder)):
        size = remainder
    received = 0
    data = StringIO()
    while (received < size):
        chunk_data = self.readchunk()
        received += len(chunk_data)
        data.write(chunk_data)
    max_chunk_n = math.ceil((self.length / float(self.chunk_size)))
    chunk = self.__chunks.find_one({'files_id': self._id, 'n': {'$gte': max_chunk_n}})
    if ((chunk is not None) and len(chunk['data'])):
        raise CorruptGridFile(('Extra    chunk    found:    expected    %i    chunks    but    found    chunk    with    n=%i' % (max_chunk_n, chunk['n'])))
    self.__position -= (received - size)
    data.seek(size)
    self.__buffer = data.read()
    data.seek(0)
    return data.read(size)
