pin_drop当前位置:知识文库 ❯ 图文
requests文件上传下载教程 - 流式下载与files参数详解
一、文件上传下载概述
requests库支持文件上传和下载功能。文件上传通过files参数实现,支持单文件和多文件上传,自动处理multipart/form-data编码。文件下载通过Response对象的content属性获取二进制数据,支持流式下载大文件。这两个功能在Web开发、自动化测试和数据处理中非常常用。
二、文件上传语法与参数
代码示例
# 文件上传
requests.post(url, files={'field': ('filename', file_obj, 'content_type')})
# 文件下载
response = requests.get(url, stream=True)
with open('filename', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
文件上传files参数格式
文件下载相关参数
三、单文件上传
使用io.BytesIO可以在内存中构建文件内容进行上传,非常适合不需要读取磁盘文件的场景。
代码示例
import requests
import io
# 方式1:上传内存中的文件内容
file_content = b'Hello, this is file content for upload!'
files = {'file': ('test.txt', io.BytesIO(file_content), 'text/plain')}
response = requests.post('https://httpbin.org/post', files=files)
result = response.json()
print(f"上传状态码: {response.status_code}")
print(f"服务器收到文件名: {result['files']['file'][:30]}...")
print(f"Content-Type: {result['headers'].get('Content-Type', '')[:40]}...")
输出结果:
代码示例
上传状态码: 200
服务器收到文件名: Hello, this is file content for uploa...
Content-Type: multipart/form-data; boundary=---...
四、多文件上传与表单混合
在实际应用中,经常需要同时上传文件和提交表单数据。requests允许同时传递files和data参数。
代码示例
import requests
import io
# 同时上传文件和提交表单数据
files = {
'document': ('report.csv', io.BytesIO(b'id,name,score\n1,Alice,95\n2,Bob,87'), 'text/csv'),
'avatar': ('photo.jpg', io.BytesIO(b'\xff\xd8\xff\xe0'), 'image/jpeg')
}
# 额外的表单数据
data = {
'user_id': '10086',
'description': '月度报告上传'
}
response = requests.post('https://httpbin.org/post', files=files, data=data)
result = response.json()
print(f"上传文件字段: {list(result['files'].keys())}")
print(f"表单数据: {result['form']}")
输出结果:
代码示例
上传文件字段: ['avatar', 'document']
表单数据: {'user_id': '10086', 'description': '月度报告上传'}
五、大文件流式下载
下载大文件时必须设置stream=True,否则整个文件会先加载到内存中,可能导致内存溢出。使用iter_content()分块读取写入是推荐的做法。
代码示例
import requests
def download_file(url, save_path, chunk_size=8192):
"""流式下载文件"""
response = requests.get(url, stream=True, timeout=30)
total_size = int(response.headers.get('content-length', 0))
downloaded = 0
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk:
f.write(chunk)
downloaded += len(chunk)
if total_size > 0:
progress = (downloaded / total_size) * 100
print(f"\r下载进度: {progress:.1f}% ({downloaded}/{total_size})", end='')
print(f"\n下载完成: {save_path}")
return save_path
# 下载示例文件
url = 'https://httpbin.org/json'
save_path = 'downloaded_data.json'
# 模拟下载(实际保存的是JSON文本)
response = requests.get(url, stream=True)
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
# 验证下载内容
with open(save_path, 'r', encoding='utf-8') as f:
print(f"文件内容前100字符: {f.read(100)}")
输出结果:
代码示例
文件内容前100字符: {
"slideshow": {
"author": "Yours Truly",
"date": "date of publication",
"slides": [
六、应用场景
-
用户头像上传:通过files参数将图片文件上传到服务器
-
数据报表下载:通过流式下载获取大型CSV或Excel文件
-
批量文件上传:同时上传多个文件和表单元数据
重要提示:上传文件时必须以二进制模式打开文件('rb'),不能使用文本模式。下载大文件时务必设置stream=True,否则整个文件会先加载到内存中。使用iter_content()时建议设置合理的chunk_size(通常8192或65536)。
七、上传下载方式对比
八、常见问题
为什么上传文件必须用'rb'模式?
文件上传使用的是multipart/form-data编码,需要传输原始字节数据。如果用文本模式('r'),Python会对数据进行编码转换(如换行符处理),可能导致文件内容损坏。
stream=True和stream=False有什么区别?
stream=False(默认)会将整个响应体加载到内存后再返回;stream=True会延迟下载响应体,允许使用iter_content()分块读取,适合下载大文件,避免内存溢出。
如何获取下载文件的原始文件名?
可以从响应头的Content-Disposition字段中提取:response.headers.get('Content-Disposition', ''),通常格式为attachment; filename="example.pdf"。
chunk_size应该设置多大合适?
通常8192(8KB)是平衡内存和性能的合理选择。对于非常大的文件,可以设置为65536(64KB)以减少IO操作次数。过小会增加IO次数,过大会增加内存占用。
本文涉及AI创作
内容由AI创作,请仔细甄别