最近在整理一个积压多年的项目文档库时,遇到了文件格式混乱的问题——同一个项目的设计文档竟然同时存在.doc、.docx、.rtf三种格式。这种情况在长期协作的项目中特别常见,不同成员使用的办公软件版本不同,就会产生这种"格式碎片化"现象。更麻烦的是,有些重要文档还被保存成了.txt纯文本格式,丢失了所有格式信息。
这种文件格式不统一的情况会带来很多实际问题:
要实现批量修改文件类型,本质上需要完成三个核心操作:
在Python生态中,这三个环节都有成熟的解决方案:
对于办公文档的转换,经过实测对比几种方案:
最终选择unoconv方案,因为:
首先需要安装必要的依赖:
bash复制# Ubuntu/Debian
sudo apt install libreoffice unoconv
pip install python-unoconv
# macOS
brew install libreoffice
pip install python-unoconv
python复制import os
import fnmatch
from unoconv import UnoConv
def batch_convert(input_dir, output_dir, input_exts, output_ext):
"""
批量转换文件格式
:param input_dir: 输入目录路径
:param output_dir: 输出目录路径
:param input_exts: 需要转换的扩展名列表,如['.doc', '.docx']
:param output_ext: 目标扩展名,如'.pdf'
"""
converter = UnoConv()
os.makedirs(output_dir, exist_ok=True)
for root, _, files in os.walk(input_dir):
for filename in files:
# 检查文件扩展名是否在目标列表中
if any(fnmatch.fnmatch(filename, f'*{ext}') for ext in input_exts):
input_path = os.path.join(root, filename)
output_path = os.path.join(
output_dir,
os.path.splitext(filename)[0] + output_ext
)
try:
converter.convert(
input=input_path,
output=output_path,
fmt=output_ext.lstrip('.')
)
print(f"转换成功: {input_path} -> {output_path}")
except Exception as e:
print(f"转换失败 {input_path}: {str(e)}")
if __name__ == '__main__':
# 示例:将当前目录下的.doc/.docx转为.pdf
batch_convert(
input_dir='.',
output_dir='./converted',
input_exts=['.doc', '.docx'],
output_ext='.pdf'
)
原始代码会将所有文件输出到同一目录,改进版本可以保持原始目录结构:
python复制def batch_convert_with_structure(input_dir, output_dir, input_exts, output_ext):
converter = UnoConv()
for root, _, files in os.walk(input_dir):
relative_path = os.path.relpath(root, input_dir)
output_root = os.path.join(output_dir, relative_path)
os.makedirs(output_root, exist_ok=True)
for filename in files:
if any(fnmatch.fnmatch(filename, f'*{ext}') for ext in input_exts):
input_path = os.path.join(root, filename)
output_filename = os.path.splitext(filename)[0] + output_ext
output_path = os.path.join(output_root, output_filename)
# 转换代码同上...
对于大量文件转换,可以使用线程池提高效率:
python复制from concurrent.futures import ThreadPoolExecutor
def convert_file(args):
input_path, output_path, converter = args
try:
converter.convert(
input=input_path,
output=output_path,
fmt=output_ext.lstrip('.')
)
return (True, input_path, output_path)
except Exception as e:
return (False, input_path, str(e))
def batch_convert_parallel(input_dir, output_dir, input_exts, output_ext, workers=4):
converter = UnoConv()
tasks = []
for root, _, files in os.walk(input_dir):
relative_path = os.path.relpath(root, input_dir)
output_root = os.path.join(output_dir, relative_path)
os.makedirs(output_root, exist_ok=True)
for filename in files:
if any(fnmatch.fnmatch(filename, f'*{ext}') for ext in input_exts):
input_path = os.path.join(root, filename)
output_filename = os.path.splitext(filename)[0] + output_ext
output_path = os.path.join(output_root, output_filename)
tasks.append((input_path, output_path, converter))
with ThreadPoolExecutor(max_workers=workers) as executor:
results = executor.map(convert_file, tasks)
for success, input_p, output_p in results:
if success:
print(f"转换成功: {input_p} -> {output_p}")
else:
print(f"转换失败 {input_p}: {output_p}")
问题现象:
解决方案:
python复制converter.convert(
input=input_path,
output=output_path,
fmt=output_ext.lstrip('.'),
options={
'pdf': {
'reduceImageResolution': False,
'quality': 100,
'embedFonts': True
}
}
)
问题现象:
优化建议:
python复制converter = UnoConv(timeout=60) # 60秒超时
对于非办公文档的转换,比如图片格式转换,可以使用Pillow库:
python复制from PIL import Image
def convert_image(input_path, output_path, output_format):
try:
img = Image.open(input_path)
img.save(output_path, format=output_format)
return True
except Exception as e:
print(f"图片转换失败 {input_path}: {str(e)}")
return False
某设计公司需要将所有历史项目文档(.doc/.ppt/.xls)统一转换为PDF归档。使用本方案后:
关键配置:
python复制batch_convert(
input_dir='/mnt/nas/projects',
output_dir='/mnt/nas/archives',
input_exts=['.doc', '.docx', '.ppt', '.pptx', '.xls', '.xlsx'],
output_ext='.pdf'
)
高校研究团队需要将所有论文草稿(.docx/.odt/.rtf)转换为LaTeX源码。解决方案:
python复制def convert_to_latex(input_path, output_path):
# 第一步:转为中间文本格式
temp_path = os.path.join('/tmp', os.path.basename(input_path) + '.txt')
converter.convert(input=input_path, output=temp_path, fmt='txt')
# 第二步:用pandoc转换
os.system(f'pandoc "{temp_path}" -o "{output_path}"')
os.remove(temp_path)
文件备份:始终先在小规模测试数据集上验证,确认无误后再处理原始文件
文件名规范:
python复制filename = filename.encode('utf-8', 'ignore').decode('utf-8')
日志记录:建议添加详细日志记录,便于排查问题:
python复制import logging
logging.basicConfig(
filename='conversion.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
bash复制# Linux/macOS
rm -rf ~/.cache/libreoffice
# Windows
del /s /q %APPDATA%\LibreOffice\4\user\temp\*