docs: def read(self, size=None):
          """
          Read at most ``size`` bytes from the file (less if we hit the end of the
          file first).  If the ``size`` argument is negative or omitted, read all
          the remaining data in the file.
  
          .. note::
              ``'b'`` mode flag is ignored (``self.FLAG_BINARY`` in
              ``self._flags``), because SSH treats all files as binary, since we
              have no idea what encoding the file is in, or even if the file is
              text data.
  
          :param int size: maximum number of bytes to read
          :return:
              data read from the file (as bytes), or an empty string if EOF was
              encountered immediately
          """
          if self._closed:
              raise IOError('File is closed')
          if not (self._flags & self.FLAG_READ):
              raise IOError('File is not open for reading')
          if (size is None) or (size < 0):
              # go for broke
              result = self._rbuffer
              self._rbuffer = bytes()
              self._pos += len(result)
              while True:
                  try:
                      new_data = self._read(self._DEFAULT_BUFSIZE)
                  except EOFError:
                      new_data = None
                  if (new_data is None) or (len(new_data) == 0):
                      break
                  result += new_data
                  self._realpos += len(new_data)
                  self._pos += len(new_data)
              return result 
          if size <= len(self._rbuffer):
              result = self._rbuffer[:size]
              self._rbuffer = self._rbuffer[size:]
              self._pos += len(result)
              return result 
          while len(self._rbuffer) < size:
              read_size = size - len(self._rbuffer)
              if self._flags & self.FLAG_BUFFERED:
                  read_size = max(self._bufsize, read_size)
              try:
                  new_data = self._read(read_size)
              except EOFError:
                  new_data = None
              if (new_data is None) or (len(new_data) == 0):
                  break
              self._rbuffer += new_data
              self._realpos += len(new_data)
          result = self._rbuffer[:size]
          self._rbuffer = self._rbuffer[size:]
          self._pos += len(result)
          return result