一、python压缩文件环境和库
python版本:3.12
1、使用 Pillow
(PIL)库对图片进行压缩,支持调整质量、尺寸和格式转换。
pip install pillow
2、使用 FFmpeg对视频压缩
# Ubuntu/Debian
sudo apt install ffmpeg
3、使用pydub(基于 FFmpeg 的封装)对音频压缩
pip install pydub
4、使用 gzip对大文件压缩
二、压缩对象并上传到minio
具体压缩到什么大小,需要结合具体对象的格式等信息
from PIL import Image
import subprocess
import gzip
from io import BytesIO
from pydub import AudioSegment
async def compress(cls, file_in: UploadFile, file_type: int, ext: str, object_name_no_ext):
# 关于参数 file_in: uniapp前端上传提交的数据,python服务端通过fastapi的UploadFile类型接收
# file_type: 上传对象的类型,10图片 20视频 30文件 40音频
# ext: 上传对象的扩展名
# object_name_no_ext:创建的对象名称(不带扩展名)/img/20260515/123EM 、 test,方便压缩后组成存储文件名,如/img/20260515/123EM.jpeg,test.ppt.gz
# 压缩文件
# 执行压缩
if file_type == 10:
# quality: 压缩质量(1 - 100)
quality = 85
img = Image.open(BytesIO(file_in.file.read()))
# 调整尺寸(可选)
# max_size = (1024, 768)
# max_size: 最大尺寸(宽, 高),如(800, 600)
# if max_size:
# img.thumbnail(max_size, Image.Resampling.LANCZOS)
# format: 输出格式(JPEG, PNG, WEBP)
img_format = "JPEG"
content_type = "image/jpeg"
new_ext = 'jpeg'
# if ext == 'png':
# img_format = 'PNG'
# content_type = "image/png"
# new_ext = 'png'
# max_size = (1920, 1080)
# img.thumbnail(max_size, Image.Resampling.LANCZOS)
# 转换为 RGB(避免 RGBA 保存 JPEG 报错)
if img.mode in ("RGBA", "P"):
img = img.convert("RGB")
compressed_data = BytesIO()
img.save(compressed_data, format=img_format, quality=quality, optimize=True)
compressed_data.seek(0)
length = len(compressed_data.getvalue())
object_name = object_name_no_ext + '.' + new_ext
return compressed_data, content_type, length, object_name, new_ext
elif file_type == 20:
# 视频压缩
# 启动 FFmpeg 进程(从 stdin 读取,输出到 stdout)
# preset: 编码速度(ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow)
# crf: 压缩质量(0 - 51,越小质量越高,建议18 - 28)
ffmpeg_cmd = [
"ffmpeg",
"-i", "pipe:0",
"-vcodec", "libx264",
"-crf", "24",
"-preset", "fast",
"-acodec", "aac",
"-f", "mp4",
"-movflags", "frag_keyframe+empty_moov", # 允许流式 MP4
"pipe:1"
]
proc = subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 写入输入数据并获取压缩后的数据
compressed_data, _ = proc.communicate(input=file_in.file.read())
compressed_data = BytesIO(compressed_data)
content_type = "video/mp4"
length = len(compressed_data.getvalue())
object_name = object_name_no_ext + '.' + 'mp4'
return compressed_data, content_type, length, object_name, 'mp4'
elif file_type == 40:
# 音频压缩
# format: 输入文件的格式(如"wav", "mp3", "flac")
# bitrate: 目标比特率(如"128k")设置音频比特率(常见值:64k(低质量)、128k(标准)、192k(高质量)
bitrate = "128k"
audio = AudioSegment.from_file(BytesIO(file_in.file.read()), format=ext)
# 导出为 MP3
compressed_data = BytesIO()
audio.export(compressed_data, format="mp3", bitrate=bitrate)
compressed_data.seek(0)
compressed_data = BytesIO(compressed_data.read())
content_type = "audio/mpeg"
length = len(compressed_data.getvalue())
object_name = object_name_no_ext + '.' + 'mp3'
return compressed_data, content_type, length, object_name, 'mp3'
else:
# 使用GZIP压缩大文件
compressed_data = BytesIO()
with gzip.GzipFile(fileobj=compressed_data, mode="wb") as gz:
gz.write(file_in.file.read())
compressed_data.seek(0)
content_type = "application/gzip"
length = len(compressed_data.getvalue())
object_name = object_name_no_ext + '.' + ext + '.gz'
return compressed_data, content_type, length, object_name, '.gz'
# 获取压缩后的数据,对象类型、压缩后的文件大小,对象存储名称,文件扩展名
compressed_data, content_type, file_size, object_name, origin_ext = await compress(file_in, file_type, ext, object_name_no_ext)
# minio上传压缩后的文件
put_config = {
'bucket_name': bucket_name,
'object_name': object_name,
'data': compressed_data,
'length': file_size,
'part_size': 10*1024*1024
}
if content_type:
put_config['content_type'] = content_type
minioClient.put_object(**put_config)