Search code examples
python-3.xftpftplib

how to write to a file on a remote server using ftplib


I need to open a file on a remote server in write mode.

I'm using the following code to write/read the file:

python
import tempfile
import io



class OpenRead(object):

    def _open_tempfile(self):
        self.tfile = tempfile.NamedTemporaryFile()
        # Write data on tempfile.
        self.ftp.retrbinary(
            'RETR %s' % self.filename, self.tfile.write)
        # Get back to start of file, so it would be possible to
        # read it.
        self.tfile.seek(0)
        return open(self.tfile.name, 'r')

    def __init__(self, ftp, filename):
        self.ftp = ftp
        self.filename = filename
        self.tfile = None

    def __enter__(self):
        return self._open_tempfile()

    def __exit__(self, exception_type, exception_value, traceback):
        # Remove temporary file.
        self.tfile.close()

class OpenWrite(object):
    def __init__(self, ftp, filename):
        self.ftp = ftp
        self.filename = filename
        self.data = ''

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        bio = io.BytesIO()
        if isinstance(self.data, six.string_types):
            self.data = self.data.encode()
        bio.write(self.data)
        bio.seek(0)
        res = self.ftp.storbinary('STOR %s' % self.filename, bio)
        bio.close()
        return res

    def write(self, data):
        self.data += data

def open(ftp, filename, mode='r'):
    """Open a file on FTP server."""
    if mode == 'r':
        return OpenRead(ftp, filename)
    if mode == 'w':
        return OpenWrite(ftp, filename)

but

python
with open(ftplib.FTP('domain.com', 'username', 'password'), 'file.txt', 'w') as file:
    file.write('hello')

throws

OpenWrite object has no atribute 'write'", 

even though context manager should have called __enter__ which calls _open_tempfile which returns an open object, though this is not the case.

How do i fix the error or is there a better way to do all this?? Thanks!


Solution

  • I figured it out now. I'm using FTP to download and re-upload the file, editing it locally as a tempfile and re-uploading the file with changes. My code is DEFINATELY not the most effective, but it works for me.

    import tempfile
    import io
    
    class WriteModeFtp:
            def __init__(self, ftp, filename, mode="a"):
                    self.ftp = ftp
                    self.filename = filename
                    self.mode = mode
                    self.load()
            def load(self):
    
                    self.tempfile = tempfile.NamedTemporaryFile()
    
                    with open(self.tempfile.name, "wb+") as tmp:
                            self.ftp.retrbinary('RETR ' + self.filename, tmp.write)
            def getThis(self):
                    return open(self.tempfile.name, self.mode)
            def flush(self):
                    self.ftp.storbinary('STOR %s' % self.filename, open(self.tempfile.name, "rb"))
    class MultiFtpStream:
            def __init__(self, ftp, mode="r"):
                    self.ftp = ftp
                    self.mode = mode
            def loadFile(self, filename):
                    return WriteModeFtp(self.ftp, filename, self.mode)