views:

123

answers:

3

With the following code I upload file.txt to a ftp server. When the file has been uploaded I delete it on my local machine.

import os
from ftplib import FTP

HOST = 'host.com'
FTP_NAME = 'username'
FTP_PASS = 'password'
filepath = 'C:\file.txt'
while True:
    try:
        ftp = FTP(HOST)
        ftp.login(FTP_NAME, FTP_PASS)
        file = open(filepath, 'r')
        ftp.storlines('STOR file.txt', file)
        ftp.quit()
        file.close() # from this point on the file should not be in use anymore
        print 'File uploaded, now deleting...'
    except all_errors as e: #EDIT: Got exception here 'timed out'
        print 'error'       #      then the upload restarted.
        print str(e)

os.unlink(filepath) # now delete the file

The code works, but sometimes (every ~10th upload) I get this error message:

Traceback (most recent call last):
in os.unlink(filepath)
WindowsError: [Error 32] The process cannot access the file
because it is being usedby another process: 'C:\file.txt'

So the file cannot be deleted because 'it has not been released' or something? I also tried to unlink the file this way:

while True: # try to delete the file until it is deleted...
    try:
        os.unlink(filepath)
        break
    except all_errors as e:
        print 'Cannot delete the File. Will try it again...'
        print str(e)

But with the "try except block" I also get the same error "The process cannot access the file because it is being usedby another process"! The script didn't even try to print the exception:

'Cannot delete the File. Will try it again...'

and just stopped (like above).

How can I make os.unlink do his job properly? Thanks!

A: 
import os
from ftplib import FTP

HOST = 'host.com'
FTP_NAME = 'username'
FTP_PASS = 'password'
filepath = 'C:\file.txt'
file = open(filepath, 'r')
while True:
    try:
        ftp = FTP(HOST)
        ftp.login(FTP_NAME, FTP_PASS)        
        ftp.storlines('STOR file.txt', file)
    except all_errors as e: #EDIT: Got exception here 'timed out'
        print 'error'       #      then the upload restarted.
        print str(e)
    else:
        ftp.quit()
        file.close() # from this point on the file should not be in use anymore
        print 'File uploaded, now deleting...'   
        os.unlink(filepath) # now delete the file
        break
ghostdog74
A: 

You need to close (file and ftp session) on the except leg of the try/except, else the file keeps being referenced by the "old" timed-out ftp session (so as a consequence you need to open the file within the while loop, not outside it) -- it's not enough to close the file and ftp session on the else leg as that doesn't get rid of the references from the failed, timed out attempts (if any).

Alex Martelli
Is it ok to just put my whole ftpupload code in a new def and the os.unlink outside the def (or even in another def)? Does this solve the ftp session problem?
creativz
@creativz, as long as you make sure the file and ftp session are closed unconditionally (including when timeouts occur), it will be fine whether they're in the same function or another one.
Alex Martelli
A: 

I have still problems with the code, it is not as robust as I need it to be. For example it is possible that the login process fails. Maybe user+pass is wrong, maybe the sesrver is busy.

try:
    ftp = FTP(HOST) # HOST is a valid host address
    ftp.login('test', 'test111111') # WRONG user + pass to test code robustness
    ftp.quit()
except all_errors as e:
    ftp.quit()
    print str(e)

The problem is the ftp.quit() in the except block. Python returns the following error (NOT exception):

Traceback (most recent call last):
    File "test.py", line 9, in <module>
        ftp.quit()
NameError: name 'ftp' is not defined
creativz