How to copy only the changed file-contents on the already existed destination file?
我有一个脚本,用于从一个位置复制到另一个位置,目录结构下面的文件都是
此脚本只计算源文件的大小,并且仅在文件大小不是零字节时进行复制。但是,我需要在一个
因此,我需要知道如何只复制源文件上更新的文件内容,然后只更新新内容的目标,而不只是覆盖目标中已经存在的内容。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/bin/python3 import os import glob import shutil import datetime def Copy_Logs(): Info_month = datetime.datetime.now().strftime("%B") # The result of the below glob _is_ a full path for filename in glob.glob("/data1/logs/{0}/*/*.txt".format(Info_month)): if os.path.getsize(filename) > 0: if not os.path.exists("/data2/logs/" + os.path.basename(filename)): shutil.copy(filename,"/data2/logs/") if __name__ == '__main__': Copy_Logs() |
我正在寻找是否有办法使用
简而言之,如果还没有复制,我只需要复制一个文件,如果源代码得到更新,那么只需要复制增量文件。
注:
编辑:
如果我们可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import os import glob import filecmp import shutil import datetime def Copy_Logs(): Info_month = datetime.datetime.now().strftime("%B") for filename in glob.glob("/data1/logs/{0}/*/*.txt".format(Info_month)): if os.path.getsize(filename) > 0: if not os.path.exists("/data2/logs/" + os.path.basename(filename)) or not filecmp.cmp("/data2/logs/" + os.path.basename(filename),"/data2/logs/"): shutil.copyfile(filename,"/data2/logs/") if __name__ == '__main__': Copy_Logs() |
您可以使用Google的diff-match补丁(您可以将其与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import diff_match_patch as dmp_module #... if not os.path.exists("/data2/logs/" + os.path.basename(filename)): shutil.copy(filename,"/data2/logs/") else: with open(filename) as src, open("/data2/logs/" + os.path.basename(filename), 'r+') as dst: dmp = dmp_module.diff_match_patch() src_text = src.read() dst_text = dst.read() diff = dmp.diff_main(dst_text, src_text) if len(diff) == 1 and diff[0][0] == 0: # No changes continue #make patch patch = dmp.patch_make(dst_text, diff) #apply it result = dmp.patch_apply(patch, dst_text) #write dst.seek(0) dst.write(result[0]) dst.truncate() |
如前所述,在需要执行增量文件列表或数据增量的情况下,
但是,您也可以指定一个变量
其次,虽然您可以使用
这里是您的最终代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/bin/python3 import os import glob import datetime import subprocess def Copy_Logs(): # Variable Declaration to get the month and Curr_date_month Info_month = datetime.datetime.now().strftime("%B") Curr_date_month = datetime.datetime.now().strftime("%b_%d_%y") Sourcedir ="/data1/logs" Destdir ="/data2/logs/" ###### End of your variable section ####################### # The result of the below glob _is_ a full path for filename in glob.glob("{2}/{0}/{1}/*.txt".format(Info_month, Curr_date_month, Sourcedir)): if os.path.getsize(filename) > 0: if not os.path.exists(Destdir + os.path.basename(filename)): subprocess.call(['rsync', '-avz', '--min-size=1', filename, Destdir ]) if __name__ == '__main__': Copy_Logs() |
pypi中的原始程序周围有过多的类
至于检查是否需要进行同步,您可以使用
这方面有一些非常有趣的想法,但我会尝试提出一些新的想法。
想法1:追踪更新的更好方法根据您的问题,很明显您正在使用cron作业来跟踪更新的文件。
如果您试图监视的文件/目录数量相对较少,我建议使用另一种方法来简化您的生活。
您可以使用Linux inotify机制,它允许您监视特定的文件/目录,并在文件写入时得到通知。
pro:您可以立即知道每一次写入,而无需检查更改。当然,您可以编写一个处理程序,它不会每次写入都更新目标,只会在X分钟内更新一个。
下面是一个使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import inotify.adapters def _main(): i = inotify.adapters.Inotify() i.add_watch('/tmp') with open('/tmp/test_file', 'w'): pass for event in i.event_gen(yield_nones=False): (_, type_names, path, filename) = event print("PATH=[{}] FILENAME=[{}] EVENT_TYPES={}".format( path, filename, type_names)) if __name__ == '__main__': _main() |
想法2:只复制更改
如果您决定使用inotify机制,那么跟踪您的状态将是微不足道的。
然后,有两种可能性:
1。总是追加新内容
如果是这种情况,您可以简单地从最后一个偏移量复制任何内容,直到文件结束。
2。新内容在随机位置写入
在这种情况下,我建议使用其他答案提出的方法:使用diff补丁。在我看来,这是迄今为止最优雅的解决方案。
以下是一些选项:
- 差异匹配修补程序
- 微分与补片
一种方法是将一行保存到一个文件中,以跟踪(在
注意:可以优化以下代码段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import datetime import glob import os import shutil Info_month = datetime.datetime.now().strftime("%B") list_of_files = sorted(glob.iglob("/data1/logs/{0}/*/*.txt".format(Info_month)), key=os.path.getctime, reverse=True) if not os.path.exists("track_modifications.txt"): latest_file_modified_time = os.path.getctime(list_of_files[0]) for filename in list_of_files: shutil.copy(filename,"/data2/logs/") with open('track_modifications.txt', 'w') as the_file: the_file.write(str(latest_file_modified_time)) else: with open('track_modifications.txt', 'r') as the_file: latest_file_modified_time = the_file.readline() should_copy_files = [filename for filename in list_of_files if os.path.getctime(filename) > float(latest_file_modified_time)] for filename in should_copy_files: shutil.copy(filename,"/data2/logs/") |
方法是,创建一个文件,其中包含系统修改的最新文件的时间戳。
检索所有文件并按修改时间排序
1 | list_of_files = sorted(glob.iglob('directory/*.txt'), key=os.path.getctime, reverse=True) |
最初,在
1 | latest_file_modified_time = os.path.getctime(list_of_files[0]) |
我只是复制所有给定的文件,并将这个时间戳写到
否则,文件就存在了(即以前复制过文件),我只需读取时间戳并将其与我在
1 | should_copy_files = [filename for filename in list_of_files if os.path.getctime(filename) > float(latest_file_modified_time)] |
实际上,跟踪最新修改的文件的时间戳还可以让您复制更改时已复制的文件:)
您需要将更改保存到某个地方,或者在文件内容更改时侦听事件。对于后者,您可以使用
如果您决定真正喜欢cron而不是增量检查更改(看门狗),那么您需要将更改存储在一些数据库中。一些基本的例子是:
1 2 3 | ID | path | state before cron 1 | /myfile.txt | hello ...| ... | ... |
然后,为了检查
如果没有
编辑:实际上:d如果文件在同一台计算机上,您甚至可能不需要数据库…这样,您就可以直接在新文件和旧文件之间进行diff+修补。
例子:
1 2 3 4 5 6 7 8 | $ echo 'hello' > old.txt && echo 'hello' > new.txt $ diff old.txt new.txt # empty $ echo 'how are you' >> new.txt # your file changed $ diff old.txt new.txt > my.patch && cat my.patch # diff is not empty now 1a2 > how are you $ patch old.txt < my.patch # apply the changes to the old file |
在具有相同
1 2 3 | from subprocess import Popen, PIPE diff = Popen(['diff', 'old.txt', 'new.txt']).communicate()[0] Popen(['patch', 'old.txt'], stdin=PIPE).communicate(input=diff) |
您必须集成一个数据库,并且可以根据文件的大小、名称和作者来记录文件。
如果有任何更新,文件的大小将发生变化,您可以相应地更新或追加。