18.8 上传文件
您一定遇到过这样的站点,那就是允许您把文件作为HTML表单的一部分上传。这个可以通过CGI脚本实现,而Python的cgi模块就支持这个操作。
下面是一个演示上传的例子。它允许用户上传一个文件,并显示出文件的大小和MD5总数。MD5总数是对于一个文件的唯一的校验数(checksum);UNIX和Linux用户可以象下面这样使用md5或md5sum指令来事先检查一个文件的MD5总数:
#!/usr/bin/env python
# CGI file example - Chapter 18 - file.cgi
import cgitb
cgitb.enable()
import cgi, os, urllib, md5
print "Content-type: text/html"
print """<HTML>
<HEAD>
<TITLE>CGI File Example</TITLE></HEAD><BODY>"""
form = cgi.FieldStorage()
if form.has_key('file'):
fileitem = form['file']
if not fileitem.file:
print "Error: not a file upload.<P>"
else:
print "Got file: %s<P>" % cgi.escape(fileitem.filename)
m = md5.new()
size = 0
while 1:
data = fileitem.file.read(4096)
if not len(data):
break
size += len(data)
m.update(data)
print "Received file of %d bytes. MD5sum is %s<P>" % \
(size, m.hexdigest())
else:
print "No file found.<P>"
print """<FORM METHOD="POST" ACTION="%s" enctype="multipart/form-data">
File: <INPUT TYPE="file" NAME="file">
""" % os.environ['SCRIPT_NAME']
print """<INPUT TYPE="submit" NAME="submit" VALUE="Submit">
</FORM>
</BODY></HTML>"""
注意这里脚本对于表单使用了POST方法。这是必须的,上传文件是不能使用GET方法的。同时还请注意表单的enctype特性,这也是上传文件所必须的。
用来上传文件的接口是“老式的”或“底层的”cgi接口。没有使用getfirst()或getlist()(因为这两个函数会把整个文件载入内存,并处理它——这显然不好),您就最好把底层数据结构看清楚。
您可以通过查看文件属性来确定您是否有上传的文件。在这里,fileitem.file(等同于form['file'].file)用来完成这个任务。浏览器提供的文件名就包含在文件名属性中。
理论上是可以通过同样的属性来上传多个文件的。然而,浏览器以及包括Python的CGI库对此支持得都不好。因此,如果您需要通过一个单一的表单来得到多个文件,您就需要提供多个INPUT标签,每个标签有不同的名称。例如,您可以使用file、file2、file3等。
测试这个程序,首先找到一个合适的文件。如果您正运行在UNIX或Linux机器上,请使用md5或md5sum指令得到文件的MD5总数。接着使用Web浏览器来访问file.cgi。您将看到提示要求您选择文件名。选择文件并点击Submit。将得到一个返回的结果,如下所示:
Got file: bash
Received file of 628684 bytes. MD5sum is c7b805fd0322950f66a12a7b664b9cf4
和您计算的MD5总数对比一下,您应该能看到它们应该是一样的。







