Python shutil copyfile - 缺少最后几行

9 浏览
0 Comments

Python shutil copyfile - 缺少最后几行

我使用shutil copyfile尝试复制文件时,通常会丢失文件的最后几kb。我做了一些研究,发现有人在这里问了类似的问题:python shutil copy function missing last few lines,但我使用的是copyfile,它似乎使用了with语句...\n

with open(src, 'rb') as fsrc:
    with open(dst, 'wb') as fdst:
        copyfileobj(fsrc, fdst)

\n所以如果这确实是某种缓冲问题,我很困惑为什么没有更多的用户遇到这个问题-我认为它应该是众所周知的。我调用copyfile非常简单,不认为我会犯错,基本上是按照标准的方式进行操作:\n

copyfile(target_file_name,dest_file_name) 

\n然而,每次我都会丢失文件的最后大约4kb左右。我也没有修改过shutil中调用的copyfile函数,它是这样的...\n

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)

\n所以我很困惑,但我想我可能即将了解一些关于刷新、缓冲或with语句的知识...帮帮我吧!谢谢。\n


\n对于Anand:\nAnand,我避免提到那些东西,因为我的感觉是那不是问题,但既然你问了...简而言之,我正在从FTP获取一个文件,检查该文件是否与我上次保存的副本不同,如果是,就下载该文件并保存副本。这段代码很绕,当我还是一个真正的纯实用主义的初学者时写的。它看起来像:\n

for filename in ftp.nlst(filematch):
    target_file_name = os.path.basename(filename)
    with open(target_file_name ,'wb') as fhandle:
    try:
        ftp.retrbinary('RETR %s' % filename, fhandle.write)
        the_files.append(target_file_name)
        mtime = modification_date(target_file_name)
        mtime_str_for_file = str(mtime)[0:10] + str(mtime)[11:13] + str(mtime)[14:16]    + str(mtime)[17:19] + str(mtime)[20:28]#2014-12-11 15:08:00.338415.
        sorted_xml_files = [file for file in glob.glob(os.path.join('\\\\Storage\\shared\\', '*.xml'))]
        sorted_xml_files.sort(key=os.path.getmtime)
        last_file = sorted_xml_files[-1]
        file_is_the_same = filecmp.cmp(target_file_name, last_file)
        if not file_is_the_same:
            print 'File changed!'
            copyfile(target_file_name, '\\\\Storage\\shared\\'+'datebreaks'+mtime_str_for_file+'.xml') 
        else:
            print 'File '+ last_file +' hasn\'t changed, doin nothin'
            continue

0
0 Comments

问题的原因可能是由于嵌套的with语句中,内部的with语句在外部的with语句之前关闭了,导致复制文件时出现了问题。解决方法是使用更简洁的方式来处理嵌套的with语句,如下所示:

with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
    copyfileobj(fsrc, fdst)

这样可以避免内部的with语句在外部的with语句之前关闭的问题,确保复制文件时的正确执行。虽然这种解决方法可能不是最优的,但是使用shutil copyfile的方式在很多情况下都是可行的。希望有更多了解的人能提供更多的见解。对于像我这样的初学者来说,使用open()和close()函数可能是一个更好的选择。

0
0 Comments

问题的出现原因是试图复制一个未关闭的文件。这就是为什么缓冲区没有被刷新的原因。将copyfileobj移到with块外面,以允许fhandle被关闭。

解决方法是将copyfileobj移到with块外面,并确保fhandle被关闭。以下是一个示例代码:

with open(target_file_name ,'wb') as fhandle:
    ftp.retrbinary('RETR %s' % filename, fhandle.write)
# 这里是您的其余代码
# 这样fhandle就被关闭了,文件完整地存储在磁盘上

在测试Anand的刷新解决方案后,我会查看这个问题。这个解决方案似乎更为基本。谢谢您的帮助,欢迎提供任何其他见解。

经过一些测试,这个解决方案也行之有效。后来看起来是如此明显。非常感谢您的帮助。

0
0 Comments

在这个问题中,最可能的问题是在执行以下行时 - ftp.retrbinary('RETR %s' % filename, fhandle.write)。这里使用fhandle.write()函数将来自ftp服务器的数据写入文件(文件名为target_file_name),但是在调用shutil.copyfile时,fhandle的缓冲区尚未完全刷新,因此在复制文件时会丢失一些数据。

为了确保不会发生这种情况,您可以将copyfile逻辑移出fhandlewith块,或者在复制文件之前调用fhandle.flush()来刷新缓冲区。

我认为最好是关闭文件(将逻辑移到with块之外)。示例 -

for filename in ftp.nlst(filematch):
    target_file_name = os.path.basename(filename)
    with open(target_file_name ,'wb') as fhandle:
        ftp.retrbinary('RETR %s' % filename, fhandle.write)
    the_files.append(target_file_name)
    mtime = modification_date(target_file_name)
    mtime_str_for_file = str(mtime)[0:10] + str(mtime)[11:13] + str(mtime)[14:16]    + str(mtime)[17:19] + str(mtime)[20:28]#2014-12-11 15:08:00.338415.
    sorted_xml_files = [file for file in glob.glob(os.path.join('\\\\Storage\\shared\\', '*.xml'))]
    sorted_xml_files.sort(key=os.path.getmtime)
    last_file = sorted_xml_files[-1]
    file_is_the_same = filecmp.cmp(target_file_name, last_file)
    if not file_is_the_same:
        print 'File changed!'
        copyfile(target_file_name, '\\\\Storage\\shared\\'+'datebreaks'+mtime_str_for_file+'.xml') 
    else:
        print 'File '+ last_file +' hasn\'t changed, doin nothin'
        continue

谢谢Anand,这个修复方法确实是我遇到的症状的第一个和最直接的修复。我还会考虑nsilent22的解决方法,这似乎更加根本。欢迎任何想法。

nslient22的解决方法是相同的,即在将文件发送到copyfile()函数之前关闭文件,方法是将copyfile(以及所有不依赖于文件句柄的逻辑)移出with块。

啊,你说得对,我专注于“flush”这个想法-但你也指定了“为了确保不会发生这种情况,您可以将copyfile逻辑移到fhandle的with块之外。”非常感谢。

(我专注于刷新的想法,因为我先看到了你的评论,然后才看到这个答案。再次感谢)。

哦,好的,抱歉,这只是为了测试是否是确切的问题(我有一个直觉,只是想确认一下)。

0