Using ftplib to upload a file to a server....

Andy Jewell andy at wild-flower.co.uk
Thu Jun 19 17:22:37 EDT 2003


On Thursday 19 Jun 2003 2:56 pm, Francois Meehan wrote:
> Hi all,
>
> Please excuse my "newbiness", but I can't get python to upload a file using
> ftplib, basically I don't make sense of the transfercmd.
>
> I can connect, return a file listing, but could not find upload example on
> the net.
>
> Could someone provide me an example? Or is there an easier modules to use
> for FTP file transfer?
>
> Francois


You may find this interesting (I'm not making any claims as to *how* 
interesting, tho).

I'm using this (in an incrementally modified state) at the moment to transfre 
files to/from AS/400 and HP-UX ftp servers, and it's working fine...

Hope it helps

-andyj

-----------------8<---------------

import ftplib
import os

localfilecache="c:/temp/ftpcache/"

class ftpfile(file):
	""" url,mode="r",buffering=-1
	
	    FTP aware file object which delegates "normal" file operations
	    to the superclass.

	    If the file name begins "ftp://", FTP mode is enabled.

	    In FTP mode, where reading of the file is required, the file is
	    first downloaded from the remote host,  and where writing is
	    required, the file is uploaded when it is closed.

	    NOTE THAT FTP READS AND WRITES ARE PERFORMED ON A LOCAL COPY
	    
	"""

	def __init__(self,name,mode="r",buffering=-1):
		if not name.startswith("ftp://"):
			return super(ftpfile).__init__(name,mode,buffering)
		self.filemode=mode		
		self.decodeurl(name)
		self.localfilename=os.path.join(localfilecache,
						self.host,self.user,
						self.path,self.filename)
		localpath=os.path.join(localfilecache,
				       self.host,self.user,
				       self.path)
		if not os.path.exists(localpath):
			os.makedirs(localpath)
		# Decide if we need to download the file first
		if self.filemode[0] not in ["w","wb"]:
			self.downloadfile(name,self.filemode)
		# Short-circuit our close() method if file doesn't need
		# to be uploaded
		if self.filemode in ["r","rb"]:
			self.close=super(ftpfile,self).close
		#self.localfilehandle=file(self.localfilename,self.filemode)
		return super(ftpfile,self).__init__(self.localfilename,mode,buffering)

	def close(self):
		# ... then upload it
		ftpconn=ftplib.FTP(self.host,self.user,self.passwd,None)
		ftpconn.cwd(self.path)
		try:
			ftpconn.delete(self.filename)
		except:
			pass
		super(ftpfile,self).close()
		self.localfilehandle=file(self.localfilename,"r")
		if "b" in self.mode:
			ftpconn.storbinary("STOR "+self.filename,self.localfilehandle)
		else:
			ftpconn.storlines("STOR "+self.filename,self.localfilehandle)			
		ftpconn.close()
		# Close the file...
		self.localfilehandle.close()
		
	def downloadfile(self,name,mode):
		# Use correct file mode
		if "b" in mode:
			retr=ftplib.FTP.retrbinary
			self.writer=self.binwriter
			localmode="wb"
		else:
			retr=ftplib.FTP.retrlines
			self.writer=self.txtwriter
			localmode="w"
		# Download the file
		if os.path.exists(self.localfilename):
			os.remove(self.localfilename)
		self.localfilehandle=file(self.localfilename,localmode)
		ftpconn=ftplib.FTP(self.host,self.user,self.passwd)
		ftpconn.cwd(self.path)
		if "b" in mode:
			ftpconn.retrbinary("RETR "+self.filename,self.binwriter)
		else:
			ftpconn.retrlines("RETR "+self.filename,self.txtwriter)
		ftpconn.close()
		self.localfilehandle.close()
			
	def decodeurl(self,url):
		""" decodes an ftp url into its component fields:

			ftp://[user[:passwd]@]host[:port]/path/filename
			     /     /       /      /      /    /
			     |     |       |      |      |    lastslash
			     |     |       |      |       firstslash
			     |     |       at     portcolon
			     |     colon
			     6
		"""

		# Sanity check:
		if not url.startswith("ftp://"):
			raise "Malformed url:",url
		
		# Do we have a user:passwd pair?
		at=url.find("@",6)
		colon=url.find(":",6)
		portcolon=url.find(":",at)
		if at == -1:
			at=6
			self.user=None
			self.passwd=None
		else:
			if colon == -1:
				colon=at
			self.user=url[6:colon]
			self.passwd=url[colon+1:at]
			if self.passwd == "":
				self.passwd=None
		firstslash=url.find("/",at)
		if firstslash == -1:
			raise "Malformed url:",url
		if portcolon !=-1:			
			self.host=url[at+1:portcolon]
			self.port=url[portcolon:firstslash]
		else:
			self.host=url[at+1:firstslash]
			self.port=":21"
		lastslash=url.rfind("/")
		if lastslash == -1:
			raise "Malformed url:",url
		self.filename=url[lastslash+1:]
		self.path=url[firstslash:lastslash]
		print self.user+":"+self.passwd+"."
		print self.host,self.path,self.filename

	def binwriter(self,block):
		self.localfilehandle.write(block)

	def txtwriter(self,line):
		self.localfilehandle.write(line+"\n")

	def write(self,string):
		print "Writing",repr(string)
		super(ftpfile,self).write(string)













More information about the Python-list mailing list