Chapter 17 ■ Ftp
323
Next, note that ntransfercmd() returns a tuple consisting of a data socket and an estimated size. Always bear in
mind that the size is merely an estimate, and it should not be considered authoritative; the file may end sooner, or it
might go on much longer than this value. Also, if a size estimate from the FTP server is simply not available, then the
estimated size returned will be None.
The object datasock is, in fact, a plain TCP socket, which has all of the behaviors described in Part 1 of this book
(see Chapter 3 in particular). In this example, a simple loop calls recv() until it has read all of the data from the
socket, writing it out to disk along the way and printing out status updates to the screen.
■ Tip Notice two things about the status updates printed to the screen by Listing 17-4. First, rather than printing a
scrolling list of lines that disappear out of the top of the terminal, each line begins with a carriage return '\r', which
moves the cursor back to your terminal’s left edge so that each status line overwrites the previous one and creates the
illusion of an increasing, animated percentage. Second, because you are telling each print statement to end the line with
a space instead of a new line, you never actually let it finish a line of output, so you have to flush() the standard output
to make sure that the status updates immediately reach the screen.
After receiving the data, it is important to close the data socket and call voidresp(), which reads the command
response code from the server, raising an exception if there was any error during transmission. Even if you do not care
about detecting errors, failing to call voidresp() will make future commands likely to fail because the server’s output
socket will be blocked waiting for you to read the results.
Here is an example of the output of running this program:
$ ./advbinarydl.py
Received 1259161 of 1259161 bytes (100.0%)
Uploading Data
File data can also be uploaded through FTP. As with downloading, there are two basic functions for uploading:
storbinary() and storlines(). Both take a command to run and a file-like object to transmit. The storbinary()
function will call the read() method repeatedly on that object until its content is exhausted, while storlines(), by
contrast, calls the readline() method.
Unlike the corresponding download functions, these methods do not require you to provide a callable function of
your own. (But you could, of course, pass a file-like object of your own crafting whose read() or readline() method
computes the outgoing data as the transmission proceeds!)
Listing 17-5 shows you how to upload a file in binary mode.
Listing 17-5. Binary Upload
#!/usr/bin/env python3
Foundations of Python Network Programming, Third Edition
https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter17/binaryul.py
from ftplib import FTP
import sys, getpass, os.path