用Python 3.x写文件到磁盘
我在使用BottlePy时,写了以下代码来上传文件并将其保存到磁盘:
upload = request.files.get('upload')
raw = upload.file.read()
filename = upload.filename
with open(filename, 'w') as f:
f.write(raw)
return "You uploaded %s (%d bytes)." % (filename, len(raw))
每次都能返回正确的字节数。
对于像 .txt
、.php
、.css
这样的文件,上传都没问题。
但是,对于其他文件,比如 .jpg
、.png
、.pdf
、.xls
等,上传后文件就会损坏。
我尝试修改 open()
函数:
with open(filename, 'wb') as f:
结果返回了以下错误:
TypeError('必须是字节或缓冲区,而不是字符串',)
我猜这可能是和二进制文件有关的问题?
有没有什么东西可以在Python上安装,以便能够上传任何类型的文件呢?
更新
为了确认,正如 @thkang 指出的,我尝试使用BottlePy的开发版本和内置方法 .save() 来编写代码:
upload = request.files.get('upload')
upload.save(upload.filename)
结果返回了完全相同的异常错误。
TypeError('must be bytes or buffer, not str',)
更新 2
这是最终的代码,它“有效”(并且没有出现错误 TypeError('必须是字节或缓冲区,而不是字符串',)
):
upload = request.files.get('upload')
raw = upload.file.read().encode()
filename = upload.filename
with open(filename, 'wb') as f:
f.write(raw)
不幸的是,结果还是一样:每个 .txt
文件都能正常工作,但其他文件如 .jpg
、.pdf
等仍然会损坏。
我还注意到那些损坏的文件(上传后)比原始文件的大小要大。
这个二进制的问题可能就是Python 3.x的一个问题。
注意:
我使用的是Python 3.1.3
我使用的是BottlePy 0.11.6 (原始的 bottle.py 文件,没有经过2to3转换或其他处理)
2 个回答
试试这个:
upload = request.files.get('upload')
with open(upload.file, "rb") as f1:
raw = f1.read()
filename = upload.filename
with open(filename, 'wb') as f:
f.write(raw)
return "You uploaded %s (%d bytes)." % (filename, len(raw))
更新
试试 value
:
# Get a cgi.FieldStorage object
upload = request.files.get('upload')
# Get the data
raw = upload.value;
# Write to file
filename = upload.filename
with open(filename, 'wb') as f:
f.write(raw)
return "You uploaded %s (%d bytes)." % (filename, len(raw))
更新 2
看看 这个讨论,它似乎和你想做的事情是一样的...
# Test if the file was uploaded
if fileitem.filename:
# strip leading path from file name to avoid directory traversal attacks
fn = os.path.basename(fileitem.filename)
open('files/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
在Python 3.x中,所有的字符串都是unicode格式,所以你需要对这个文件上传代码中的read()
函数进行一些转换。
read()
函数返回的也是一个unicode字符串,你可以通过encode()
函数把它转换成合适的字节格式。
使用我第一个问题中的代码,把这一行
raw = upload.file.read()
替换成
raw = upload.file.read().encode('ISO-8859-1')
就可以了;)
想了解更多,可以看看这个链接:http://python3porting.com/problems.html