前几天我基于plupload改写的文件上传模块出问题了,在本地测试的时候,只要不高于2G是没问题的,但给另外一个单位部署的那套系统居然只能上传不大于1M的文件。考虑到之前的上传也出现过不稳定的情况,接上级通知,重新写一下这个模块。
写是没问题,问题的关键是找到到底是什么原因导致的上传不靠谱。
文件上传应该包括两部分,一个数据传输的部分,一个是数据接收部分。
数据接收部分是用django写的,先看一下django是如何处理用户上传的数据的。
Django会把用户上传过来的文件封装到UploadFile类里,如果是大文件(默认大于2.5M)就先以临时文件存储,如果是小文件就直接读到内存中。以临时文件存储的类是TemporaryUploadedFile,存在内存中的文件是InMemoryUploadedFile。
UploadFile对象有如下方法:
1、UploadFile.read():
从文件中读取全部上传数据。当上传文件过大时,可能会耗尽内存,慎用。
2、UploadFile.multiple_chunks():
如上传文件足够大,要分成多个部分读入时,返回True.默认情况,当上传文件大于2.5M时,返回True。但这一个值可以配置。
3、UploadFile.chunks():
返回一个上传文件的分块生成器。如multiple_chunks()返回True,必须在循环中使用chrunks()来代替read()。一般情况下直接使用chunks()就行。
4、UploadFile.name():上传文件的文件名
5、UplaodFile.size():上传文件的文件大小(字节)
由上面的说明可以写出handle_uploaded_file函数
def handle_uploaded_file(f): destination = open('some/file/name.txt', 'wb+') for chunk in f.chunks(): destination.write(chunk) destination.close()
关于文件的接受和存储可以在settings.py中进行设置:
FILE_UPLOAD_MAX_MEMORY_SIZE:直接读入内存的最大上传文件大小(字节数)。当大于此值时,文件存放到磁盘。默认2.5M字节
FILE_UPLOAD_TEMP_DIR:临时文件的存储目录
POST /home/upload HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:8000/home/index
Cookie: csrftoken=YHb....bnTbIw_xk33P6xujZmU"
Connection: keep-alive
Content-Length 8981
Content-Type multipart/form-data; boundary=---------------------------19470111021138404276570831403
Content-Disposition: form-data; name="file"; filename="track.shp.xml" Content-Type: text/xml
文件内容
boundary=-----------------------------19470111021138404276570831403
Content-Disposition: form-data; name="submit" Submit
boundary=-----------------------------19470111021138404276570831403--
也就是说,文件在http这一层是没有被分割的,通过两个boundary界定,可以通过filename来识别,通过wireshark可以发现,真正的数据分片是发生在TCP层的。