用Python 3.x写文件到磁盘

3 投票
2 回答
19011 浏览
提问于 2025-04-17 19:23

我在使用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的一个问题。

注意:

2 个回答

3

试试这个:

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'
2

在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

撰写回答