程序的基本思路是在数据库中存储文件名和他的MD5信息,校验这两个数据,如果数据库里面没有就转换,如果有就不转换,如果文件名有但MD5不同,就要删除原有的数据条目,避免word文档回到旧版本时转换不了
import subprocess
# from win32com.client import gencache
# from win32com.client import constants, gencache
import os
import sys
import hashlib
import pymysql
#读取MD5
def readMD5(path):
with open(path, 'rb') as fp:
data = fp.read()
file_md5 = hashlib.md5(data).hexdigest()
return file_md5
def checkMD5(md5,filename):
# 拿到套接字对象
client = pymysql.connect(
host='mysql',
port=3306,
user='root',
password='sa123456',
database='db1',
charset='utf8'
)
# 拿到游标 mysql>
# cursor() 只会把每条记录放入小元组
cursor=client.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS `docxmd5` (
`mymd5` varchar(32) NOT NULL,
`filename` varchar(150) NOT NULL,
PRIMARY KEY (`mymd5`,`filename`)
)
''')
client.commit()
sql=f"select * from docxmd5 where mymd5='{md5}' and filename='{filename}'"
rows=cursor.execute(sql)
if rows:
cursor.close()
client.close()
return 0
else:
sql2=f"insert into docxmd5 (mymd5,filename) value ('{md5}','{filename}')"
cursor.execute(sql2)
client.commit()
cursor.close()
client.close()
return 1
def findoldMD5(filename):
client = pymysql.connect(
host='mysql',
port=3306,
user='root',
password='sa123456',
database='db1',
charset='utf8'
)
# 拿到游标 mysql>
# cursor() 只会把每条记录放入小元组
cursor = client.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS `docxmd5` (
`mymd5` varchar(32) NOT NULL,
`filename` varchar(150) NOT NULL,
PRIMARY KEY (`mymd5`,`filename`)
)
''')
client.commit()
sql = f"select * from docxmd5 where filename='{filename}'"
rows = cursor.execute(sql)
if rows:
data=cursor.fetchone()
cursor.close()
client.close()
return data[0]
else:
cursor.close()
client.close()
return 0
def deleteMD5(oldmd5, filename):
client = pymysql.connect(
host='mysql',
port=3306,
user='root',
password='sa123456',
database='db1',
charset='utf8'
)
# 拿到游标 mysql>
# cursor() 只会把每条记录放入小元组
cursor = client.cursor()
sql=f"delete from docxmd5 where mymd5='{oldmd5}' and filename='{filename}"
#创建PDF windows-version
'''
def createPdf(wordPath, pdfPath):
"""
word转pdf
:param wordPath: word文件路径
:param pdfPath: 生成pdf文件路径
"""
word = gencache.EnsureDispatch('Word.Application')
doc = word.Documents.Open(wordPath, ReadOnly=1)
doc.ExportAsFixedFormat(pdfPath,
constants.wdExportFormatPDF,
Item=constants.wdExportDocumentWithMarkup,
CreateBookmarks=constants.wdExportCreateHeadingBookmarks)
word.Quit(constants.wdDoNotSaveChanges)
'''
#遍历当前目录,并把Word文件转换为PDF
def doc2pdf_linux(docPath):
cmd = 'libreoffice --headless --convert-to pdf'.split() + [docPath]
p = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
p.wait(timeout=30)
stdout, stderr = p.communicate()
if stderr:
raise subprocess.SubprocessError(stderr)
def wordToPdf(path):
# 获取当前运行路径
# path = os.listdir(loc)
# 获取所有文件名的列表
# print(path)
try:
filename_list = os.listdir(path)
except:
print('没有这个文件夹')
return 0
# print(filename_list)
print('文件夹:',path,"转换中...")
# 获取所有word文件名列表
wordname_list = [filename for filename in filename_list \
if filename.endswith((".docx",))]
for wordname in wordname_list:
# 分离word文件名称和后缀,转化为pdf名称
pdfname = os.path.splitext(wordname)[0] + '.pdf'
wordpath = os.path.join(path, wordname)
pdfpath = os.path.join(path, pdfname)
oldmd5=0
if os.path.exists(pdfpath):
oldmd5=findoldMD5(wordpath)
md5=readMD5(wordpath)
if not checkMD5(md5,wordpath):
print(wordpath,'已经转换过了')
continue
else:
#将旧文件信息删除
if oldmd5!=0:
deleteMD5(oldmd5,wordpath)
print(wordpath,pdfpath,end='\n')
doc2pdf_linux(wordpath)
#word转pdf
if __name__ == '__main__':
try:
path:str=sys.argv[1]
except:
# 如果参数不提供就是当前目录
path=os.getcwd()
try:
path=os.path.abspath(path)
print('当前绝对路径为:',path)
pathlist=os.walk(path)
except:
print(f'文件夹位置{path}错误,未能找到!')
exit()
for i in pathlist:
wordToPdf(i[0])
读取word文件的MD5值
连接数据库并创建表,查询这个MD5与文件名,有就返回0,没有就插入并返回1
在相关pdf文件已经存在的情况下,查询旧文件的MD5并返回
删除旧的MD5和文件名的数据
在linux下调用系统命令转换文件
主程序,对路径下的以docx结尾的文件遍历并调度上面的几个函数,安排数据库读取,存储和 删除
程序入口接受一个命令行参数作为路径,也默认使用当前文件的位置作为路径,利用os.walk函数逐层遍历路径并调用wordToPdf函数
windows下的pdf转换,在windows下可以直接调用这个函数转换
version: "3.1"
services:
# python环境
libreoffice:
tty: true
stdin_open: true
build: code
volumes:
- ./code:/code
# mysql
mysql:
image: "mysql:latest"
environment:
MYSQL_ROOT_PASSWORD: sa123456
MYSQL_DATABASE: db1
ports:
- 3307:3306
这里建立了两个容器服务
libreoffice是一个带python的环境,具体的构建参照code文件夹下的Dockerfile
将目录下的code文件夹映射到容器中的code文件夹
mysql建立一个数据库服务,对应python文件代码里的连接,host参数的名字就是服务名mysql
FROM gocept/libreoffice-python:py3.6
WORKDIR /code
RUN python -m pip install --upgrade pip
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
libreoffice基于的镜像是gocept/libreoffice-python:py3.6
镜像在https://hub.docker.com/u/library自己选择
找个带libreoffice的 且有python的pip的,没有pip的需要自己装
比如这个镜像
FROM instructure/libreoffice:6.2
WORKDIR /code
USER root
RUN apt-get update
RUN apt -y install python3-pip
#RUN pip3 install --upgrade pip3
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
PyMySQL
cryptography
这只需要两个即可
后面那个是用来在数据库里连接时避免出现
RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods
那个pip版本要更新,所以Dockerfile升级了pip