为什么我不能打开使用此代码复制的pdf文件

时间:2014-06-12 17:43:52

标签: python pdf file-io

我需要对一些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 个答案:

答案 0 :(得分:2)

  

我无法弄清楚为什么我无法将该文件作为字符串读取,然后将其写入新位置。

请注意,PDF是二进制文件格式,而不是文本文件格式。将文件(或一般数据)作为文本处理的方法可能会以不同的方式对其进行更改,尤其是:

  • 以文本形式读取数据根据某些字符编码将字节和字节序列解释为字符。将文本作为数据再次写回也会根据某些字符编码进行转换。

    如果应用的编码不同,结果显然与原始文件不同。但即使使用相同的编码,差异也会蔓延:如果原始文件包含在应用的编码中没有意义的字节,则使用一些替换字符而最终结果文件包含该替换字符的编码,而不是原始字节序列。此外,一些编码对于相同的字符具有多种可能的编码。因此,某些输入字节序列可能被表示输出中相同字符的某些其他序列替换。

  • 可以根据平台的偏好更改行尾序列。

    二进制文件可以包含在一个或另一个平台上用作行尾标记的不同字节序列,例如, CR,LF,CRLF,...将数据视为文本的方法可以用本地平台所支持的一个序列替换所有这些数据。但由于二进制文件中的这些字节可能与行尾有不同的含义,因此这种替换可能具有破坏性。

  • 通常可以忽略控制字符

    在许多编码中,字节0..31具有作为控制字符的含义。将二进制数据视为文本的方法可能会以某种方式解释它们,这可能会导致输出再次发生变化。

所有这些变化都可以完全破坏二进制数据,例如: PDF中的压缩流。

您可以尝试使用二进制模式读取文件,方法是在模式字符串中使用 b 打开它们。在阅读和写作时使用二进制模式可以解决您的问题。

  

我做的一件事是比较从源读取的内容与文件内容在阅读后的内容之后的内容:

>>> newstring = open(newpath + '\\' +fileName).read()
>>> newstring == fstring
True
     

所以内容没有改变?

您的比较也会将文件作为文本读取。因此,您不会比较原始文件和复制文件的实际字节内容,而是根据读取时假定的编码进行解释。因此,比较的双方都已经造成了损害。

答案 1 :(得分:1)

您应该使用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类型操作。