为什么我无法打开用此代码复制的pdf文件
我需要处理一些PDF文件。作为第一步,我想把它们从一个文件夹复制到一个符合我需求的文件树里。我用了以下的代码:
for doc in docList:
# these steps just create the directory structure I need from the file name
fileName = doc.split('\\')[-1]
ID = fileName.split('_')[0]
basedate = fileName.split('.')[0].split('_')[-1].strip()
rdate = '\\R' + basedate + '-' +'C' + basedate
newID = str(cikDict[ID])
newpath = basePath + newID + rdate
# check existence of the new path
if not os.path.isdir(newpath):
os.makedirs(newpath)
# reads the file in and then writes it to the new directory
fstring = open(doc).read()
outref = open(newpath +'\\' + fileName, 'wb')
outref.write(fstring)
outref.close()
当我运行这段代码时,文件夹被创建了,每个文件夹里都有正确名称的文件。然而,当我点击打开一个文件时,Acrobat给我提示说文件损坏,无法修复。
我用以下代码成功复制了文件:
shutil.copy(doc,newpath)
我想用这个来替换最后四行代码,但我还没弄明白为什么我不能把文件当作字符串读取,然后再写到新的位置。
我做的一件事是比较从源文件读取的内容和在写入后再读取的文件内容:
>>> newstring = open(newpath + '\\' +fileName).read()
>>> newstring == fstring
True
所以看起来内容并没有改变?
2 个回答
我一直搞不明白为什么我不能把文件当成字符串来读取,然后再写到一个新的位置。
请注意,PDF文件是一种二进制文件格式,而不是文本文件格式。把文件(或者一般的数据)当作文本来处理可能会以不同的方式改变它,特别是:
把数据当作文本读取时,会根据某种字符编码把字节和字节序列解释成字符。再把文本写回数据时,也会根据某种字符编码进行转换。
如果使用的编码不同,结果显然会和原始文件不同。但即使使用的是相同的编码,也可能会出现差异:如果原始文件中包含的字节在所用编码中没有意义,就会用某个替代字符来代替,最终结果文件中包含的是那个替代字符的编码,而不是原始的字节序列。此外,有些编码对于同一个字符可能有多种编码方式。因此,某些输入的字节序列可能会被替换成输出中表示同一字符的其他序列。
换行符的序列可能会根据平台的偏好而改变。
二进制文件可能包含不同的字节序列作为换行符,比如CR、LF、CRLF等。把数据当作文本处理的方法可能会把它们都替换成本地平台偏好的那种序列。但由于这些字节在二进制文件中可能有不同的含义,这种替换可能会造成破坏。
控制字符通常可能会被忽略。
在许多编码中,字节0到31有作为控制字符的含义。把二进制数据当作文本处理的方法可能会以某种方式解释它们,这也可能导致输出发生变化。
所有这些变化都可能彻底破坏二进制数据,比如PDF中的压缩流。
你可以尝试以二进制模式读取文件,方法是在模式字符串中加上b。在读取和写入时都使用二进制模式可能会解决你的问题。
我做的一件事是比较从源文件读取的内容和在写入后读取的文件内容:
>>> newstring = open(newpath + '\\' +fileName).read() >>> newstring == fstring True
所以看起来内容没有被改变?
你的比较也是把文件当作文本来读取的。因此,你并没有比较原始文件和复制文件的实际字节内容,而是根据读取时假定的编码对它们的解释进行比较。所以在你比较的两边,损坏已经发生了。
你应该使用 shutil 来复制文件。这个工具会根据你使用的操作系统来处理文件,能避免很多麻烦。
不过你已经发现这一点了。
你最好用 with 来打开和关闭文件。这样文件会自动打开和关闭,更加方便:
with open(doc, 'rb') as fin, open(fn_out, 'wb') as fout:
fout.write(fin.read()) # the ENTIRE file is read with .read()
如果你可能在处理一个大文件,建议分块读取和写入:
with open(doc, 'rb') as fin, open(fn_out, 'wb') as fout:
while True:
chunk=fin.read(1024)
if chunk:
fout.write(chunk)
else:
break
注意在 open 函数中使用的 'rb' 和 'wb' 参数。因为你是在 Windows 系统下打开这个文件,这样可以避免把文件内容误解为 Windows 字符串。
你还应该使用 os.path.join,而不是像 newpath + '\\' +fileName
这样的拼接方式。