« test | メイン | お題2:単語数カウント »

お題1:ファイルの同期

二つのディレクトリ下のタイムスタンプを比較して、同期を取るプログラムを作りたい。


二つのディレクトリ(フォルダ)を指定すると、そのディレクトリの下の全てのファイルについて「片方にしかないファイルはもう片方へコピーし、両方にあるけどもタイムスタンプ(更新時刻)の異なるファイルは新しい方で古い方を上書きする」という処理を行うプログラムを作りなさい。

トラックバック

このエントリーのトラックバックURL:
http://www.nishiohirokazu.org/mt/mt-tb.cgi/598

この一覧は、次のエントリーを参照しています: お題1:ファイルの同期:

» [python] Workshop Edge2007 お題1 -- Synchronizing Directory 送信元 Fomalhaut of Piscis Australis
ディレクトリの同期を行うプログラムです。 先週見た時は集合演算を使った回答がなかったので、わたしは集合演算を取り入れてみました。 指定したディレクトリの... [詳しくはこちら]

コメント (58)

H.K.:
#!/usr/bin/env python
#coding:utf-8

# author H.K.
# date 2007.6.12
# 2つのディレクトリ間でファイルの同期をとる

# Usage
# ./sync.py dir1 dir2

# 使用方法の表示
def usage():
    print "synchronize two directories."
    print "Usage : ./sync.py dir1 dir2"

# dir1,dir2間で同期をとる
# @param dir1 ディレクトリ1
# @param dir2 ディレクトリ2
def sync(dir1 , dir2):
    import os
    files1 = os.listdir(dir1)
    files2 = os.listdir(dir2)
    (f1to2,f2to1,fconf) = conflict(files1 , files2)
    fcopy(dir1 , dir2 , f1to2)
    fcopy(dir2 , dir1 , f2to1)
    resolveConf(dir1 , dir2 , fconf)

# コンフリクトを起こしている要素を抽出
# @param ls1 リスト1
# @param ls2 リスト2
# @return (ls1only , ls2only , conf)
# ls1only リスト1に固有の要素
# ls2only リスト2に固有の要素
# conf コンフリクトを起こしている要素
def conflict(ls1 , ls2):
    ls1only = []
    ls2only = ls2[:]
    conflicted = []
    for elem in ls1:
        if elem in ls2only:
            ls2only.remove(elem)
            conflicted.append(elem)
        else:
            ls1only.append(elem)
    return (ls1only , ls2only , conflicted)

# @param dir1 コピー元ディレクトリ
# @param dir2 コピー先ディレクトリ
# @param files dir1内に存在するコピー対象ファイル名
def fcopy(dir1 , dir2 , files):
    import shutil
    for f in files:
        p1 = dir1 + "/" + f
        shutil.copy(p1 , dir2)

# コンフリクトの解消
# @param dir1 操作対象ディレクトリ1
# @param dir2 操作対象ディレクトリ2
# @param files コンフリクトしているファイル名 (dir1,dir2内に存在)
def resolveConf(dir1 , dir2 , files):
    import os
    import shutil
    for f in files:
        p1 = dir1 + "/" + f
        p2 = dir2 + "/" + f
        t1 = (os.stat(p1)).st_mtime
        t2 = (os.stat(p2)).st_mtime
        # 最終更新時刻の比較
        if t1>t2:
            shutil.copy(p1 , dir2)
        else:
            shutil.copy(p2 , dir1)

if __name__=="__main__":
    import sys
    if len(sys.argv) != 3:
        usage()
        sys.exit()
    dir1 = sys.argv[1]
    dir2 = sys.argv[2]
    sync(dir1 , dir2)
maki:
# vim: fileencoding=utf-8
import os
import shutil

def sync(a, b):
    """ usage: python sync.py dir1 dir2 """

    a, b = os.path.abspath(a), os.path.abspath(b)

    for a_dir, _, files in os.walk(a):
        b_dir = os.path.join(b, a_dir.split(a)[1][1:])
        if not os.path.exists(b_dir):
            print "mkdir %s" % (b_dir,)
            os.mkdir(b_dir)
            sync(a_dir, b_dir)

        for f in files:
            a_path = os.path.join(a_dir, f)
            b_path = os.path.join(b_dir, f)
            if os.path.exists(b_path):
                # compare the mtime
                a_st = os.stat(a_path)
                b_st = os.stat(b_path)
                if a_st.st_mtime > b_st.st_mtime:
                    print "overwrite %s" % (b_path,)
                    shutil.copy(a_path, b_path)
            else:
                # copy file
                print "copying file: %s" % (b_path)
                shutil.copy(a_path, b_path)

if __name__ == "__main__":
    import sys
    if len(sys.argv) != 3:
        print sync.__doc__
        sys.exit(0)
    sync(sys.argv[1], sys.argv[2])
    sync(sys.argv[2], sys.argv[1])
#!/usr/bin/env python
# -*- coding: sjis -*-

import os
import shutil
from stat import *

DIR1 = "/home/xxxxxx/python/test1"
DIR2 = "/home/xxxxxx/python/test2"

S1 = set(os.listdir(DIR1))
S2 = set(os.listdir(DIR2))

for i in S1 & S2:
    F1 = DIR1 + os.sep + i
    F2 = DIR2 + os.sep + i
    ret = cmp(os.stat(F1)[ST_MTIME], os.stat(F2)[ST_MTIME])
    if ret  0:
        shutil.copy2(F1, F2)

for i in S1 - S2:
    shutil.copy2(DIR1 + os.sep + i, DIR2)

for i in S2 - S1:
    shutil.copy2(DIR2 + os.sep + i, DIR1)

上のは一部コードが消えてしまったので再投稿。不等号(<>)が絡むとコードが消えちゃいますね。

#!/usr/bin/env python
# -*- coding: sjis -*-

import os
import shutil
from stat import *

DIR1 = "/home/shun/myself/src/python/test1"
DIR2 = "/home/shun/myself/src/python/test2"

S1 = set(os.listdir(DIR1))
S2 = set(os.listdir(DIR2))

for i in S1 & S2:
  F1 = DIR1 + os.sep + i
  F2 = DIR2 + os.sep + i
  ret = cmp(os.stat(F1)[ST_MTIME], os.stat(F2)[ST_MTIME])
  if ret > 0:
    shutil.copy2(F1, F2)
  elif ret < 0:
    shutil.copy2(F2,F1)

for i in S1 - S2:
  shutil.copy2(DIR1 + os.sep + i, DIR2)

for i in S2 - S1:
  shutil.copy2(DIR2 + os.sep + i, DIR1)

hiroffff:
#! /usr/bin/env python
# -*- coding: shift-jis -*-
'''
http://www.nishiohirokazu.org/pwe2007/2007/06/post.html
'''
import os, shutil

class FileSync:
    '''
    お題1:ファイルの同期
    二つのディレクトリ下のタイムスタンプを比較して、同期を取るプログラムを作りたい。

    二つのディレクトリ(フォルダ)を指定すると、そのディレクトリの下の全てのファイル
    について「片方にしかないファイルはもう片方へコピーし、両方にあるけども
    タイムスタンプ(更新時刻)の異なるファイルは新しい方で古い方を上書きする」
    という処理を行うプログラムを作りなさい。
    '''
    def __init__(self, dirA, dirB):
        'dirA, dirBが無い場合、NameErrorの"NoDir"。'
        self.dirA = dirA
        self.dirB = dirB
        try:
            self.Aset = set(os.listdir(dirA))
            self.Bset = set(os.listdir(dirB))
        except:
            raise NameError, "NoDir"

        self.ABlist = []
        self.BAlist = []

    def __file_comp(self):
        'Aset, Bset より ABlist,BAlistを作る。'
        for f in self.Aset & self.Bset:
            Atime = os.stat(self.dirA+ os.sep +f).st_mtime
            Btime = os.stat(self.dirB+ os.sep +f).st_mtime
            if Atime > Btime:
                self.ABlist.append(f)
            if Atime < Btime:
                self.BAlist.append(f)
        for f in self.Aset - self.Bset:
            self.ABlist.append(f)
        for f in self.Bset - self.Aset:
            self.BAlist.append(f)
            
    def __file_copy(self):
        'ABlist, BAlist 順にコピーする。'
        for f in self.ABlist:
            shutil.copy2(self.dirA+ os.sep +f, self.dirB+ os.sep +f)
        for f in self.BAlist:
            shutil.copy2(self.dirB+ os.sep +f, self.dirA+ os.sep +f)
               
    def go(self):
        self.__file_comp()
        self.__file_copy()
        
if __name__ == "__main__":
    import sys
    def usage():
        print 'usage: (python) %s dir1 dir2' % sys.argv[0]
        print 'dir1 とdir2を同期させます。'

    if len(sys.argv) !=2:
        print 'test start'
        dir1 = "test1"
        dir2 = "test2"

        os.mkdir(dir1)
        os.mkdir(dir2)

        for i in range(3):
            fp = file(dir1 + os.sep + hex(i),'w')
            fp.write(hex(i))
            fp.close()

        for i in range(2,6):
            fp = file(dir2 + os.sep + hex(i),'w')
            fp.write(hex(i))
            fp.close()

        ck = ['0x0', '0x1', '0x2', '0x3', '0x4', '0x5']    
        fs = FileSync(dir1, dir2)
        fs.go()
        if ck == os.listdir(dir1):
            print 'test ok! %s の test1 test2 フォルダーを消してください。\n' %\
                  os.path.dirname(sys.argv[0])
        usage()
        
    else:
        fs = FileSync(sys.argv[1], sys.argv[2])
        fs.go()
__unko__:
# -*- coding: shift-jis -*-
import os

"""
ディレクトリのシンクロナイズ
"""
def syncDir(dir1, dir2):
	if not (os.path.exists(dir1) & os.path.exists(dir2)):
		if os.path.exists(dir1):
			os.mkdir(dir2);
		else:
			os.mkdir(dir1);
	list = set( os.listdir(dir1) + os.listdir(dir2) );
	for f in list:
		fp1 = os.path.join(dir1,f);
		fp2 = os.path.join(dir2,f);
		
		print fp1
		if os.path.isdir(fp1) | os.path.isdir(fp2):
			# ディレクトリの場合再起
			syncDir(fp1, fp2);
		elif os.path.exists(fp1) & os.path.exists(fp2):
			if cmp(fp1, fp2) != True:
				# 異なるファイルの場合、タイムスタンプを確認
				t1 = os.path.getmtime(fp1);
				t2 = os.path.getmtime(fp2);
				if t1 < t2:
					copy(fp1, fp2);
				else:
					copy(fp2, fp1);
		else:
			# どちらかのファイルが存在しない場合は存在する方のファイルを使用する
			if os.path.exists(fp1):
				copy(fp1, fp2);
			else:
				copy(fp2, fp1);

"""
f1 -> f2へコピーを行う関数
"""
def copy(f1, f2):
	rf = open(f1, "rb");
	wf = open(f2, "wb");
	for l in rf:
		wf.write(l);
	wf.close();
	rf.close();


"""
比較を行う関数
Windowsだとos.path.samefileが使えない?
"""
def cmp(f1, f2):
	rFlg = True;
	
	rf1 = open(f1, "rb");
	rf2 = open(f2, "rb");
	while True:
		s1 = rf1.readline();
		s2 = rf2.readline();
		if s1 != s2:
			rFlg = False;
			break;
		elif s1 == "":
			break;
	rf1.close();
	rf2.close();
	return rFlg;

d1 = "C:\Documents and Settings\Administrator\デスクトップ\あああ";
d2 = "C:\Documents and Settings\Administrator\デスクトップ\いいい";
syncDir(d1, d2);



__unko__:
#!/usr/bin/python
# -*- coding: shift-jis -*-
import os

"""
ディレクトリのシンクロナイズ
"""
def syncDir(dir1, dir2):
	if not (os.path.exists(dir1) & os.path.exists(dir2)):
		if os.path.exists(dir1):
			os.mkdir(dir2);
		else:
			os.mkdir(dir1);
	list = set( os.listdir(dir1) + os.listdir(dir2) );
	for f in list:
		fp1 = os.path.join(dir1,f);
		fp2 = os.path.join(dir2,f);
		
		print fp1
		if os.path.isdir(fp1) | os.path.isdir(fp2):
			# ディレクトリの場合再起
			syncDir(fp1, fp2);
		elif os.path.exists(fp1) & os.path.exists(fp2):
			if cmp(fp1, fp2) != True:
				# 異なるファイルの場合、タイムスタンプを確認
				t1 = os.path.getmtime(fp1);
				t2 = os.path.getmtime(fp2);
				if t1 < t2:
					copy(fp1, fp2);
				else:
					copy(fp2, fp1);
		else:
			# どちらかのファイルが存在しない場合は存在する方のファイルを使用する
			if os.path.exists(fp1):
				copy(fp1, fp2);
			else:
				copy(fp2, fp1);

"""
f1 -> f2へコピーを行う関数
"""
def copy(f1, f2):
	rf = open(f1, "rb");
	wf = open(f2, "wb");
	for l in rf:
		wf.write(l);
	wf.close();
	rf.close();


"""
比較を行う関数
Windowsだとos.path.samefileが使えない?
"""
def cmp(f1, f2):
	rFlg = True;
	
	rf1 = open(f1, "rb");
	rf2 = open(f2, "rb");
	while True:
		s1 = rf1.readline();
		s2 = rf2.readline();
		if s1 != s2:
			rFlg = False;
			break;
		elif s1 == "":
			break;
	rf1.close();
	rf2.close();
	return rFlg;

d1 = "C:\Documents and Settings\Administrator\デスクトップ\あああ";
d2 = "C:\Documents and Settings\Administrator\デスクトップ\いいい";
syncDir(d1, d2);



海坊主:
import os
import shutil

def rmdir(dir):
    if os.path.isdir(dir):
        shutil.rmtree(dir)

def mkdir(dir):
    if not os.path.isdir(dir):
        os.makedirs(dir)

def mkfile(path, time):
    mkdir(os.path.dirname(path))
    open(path, "w").write(path)
    os.utime(path, (time, time))

def sync(dir1, dir2):
    def half_sync(dir1, dir2): # only copy from dir1 to dir2
        for name in os.listdir(dir1):
            path1 = os.path.join(dir1, name)
            path2 = os.path.join(dir2, name)
            if os.path.exists(path2):
                time1 = os.stat(path1).st_mtime
                time2 = os.stat(path2).st_mtime
                if time1 <= time2:
                    continue
            shutil.copy2(path1, path2)
    half_sync(dir1, dir2)
    half_sync(dir2, dir1)

def show(*dirs):
    print "//////////////////////////////////////"
    for dir in dirs:
        for name in os.listdir(dir):
            path = os.path.join(dir, name)
            print (path, "source is " + open(path).read(), str(os.stat(path).st_mtime))
        print

def main():
    rmdir("foo")
    rmdir("boo")
    mkfile("foo/a.txt", 1000)
    mkfile("foo/b.txt", 2000)
    mkfile("foo/c.txt", 3000)
    mkfile("foo/d.txt", 0)
    mkfile("boo/a.txt", 2000)
    mkfile("boo/b.txt", 2000)
    mkfile("boo/c.txt", 2000)
    mkfile("boo/e.txt", 0)
    show("foo", "boo")
    sync("foo", "boo")
    show("foo", "boo")

if __name__ == '__main__':
    main()


11日にみたときは集合演算を使っている人がいないので、と思ったら集合演算使ったコードが・・・(´・ω・`)

・集合演算を使う
・module Doc String 除いて20行が目標

の2点を目指して書きました。
行数は31行でオーバー_| ̄|○

"""
Function get_filelist( dir_path )
    Return a list of files with each absolute path.
    dir_path is starting directory. If subdirectories exist,
    the files in those subdirectories are picked all up.

Function get_timestamp( filename )
    Return a timestamp of the file.

Function get_dir_info( dir_path )
    Return a dictionary of which keys are file name and values are timestamp.
    This function depends on get_filelist() and get_timestamp() defined in this module.

Function synchronize_directories( dir1, dir2 )
    Synchronize directories. If the file exist in only one-side, copy the file into other.
    If the same files exist, compare each time stamp and the older is replaced by the later.
"""
import os, shutil, stat

get_timestamp = lambda filename: os.stat( filename )[stat.ST_MTIME]
get_filelist  = lambda dir_path: [os.path.join( node[0], filename ) for node in os.walk( dir_path ) for filename in node[2]]
get_dir_info  = lambda dir_path: dict( zip( get_filelist( dir_path ), [get_timestamp( filename ) for filename in get_filelist( dir_path )] ) )

def synchronize_directories( dir1, dir2 ):
    (dir1_info, dir2_info) = map( get_dir_info, (dir1, dir2) )
    (symmetric_difference, intersection) = map( lambda method: eval( set.%s( set([filename[len( dir1 ):] for filename in dir1_info.keys()]), set([filename[len( dir2 ):] for filename in dir2_info.keys()]) ) % method ), ["symmetric_difference", "intersection"] )

    # copies lacked files
    # It is necessary to make intermediate path before copying or replacing file.
    # For example, imagine dir_path=X:\hoge and filename=X:\hoge\piyo\fuge\bar.txt. In this case, intermediate path is /piyo/hoge.
    # At first, using expression "os.path.split( orz )[0][len( dir_path ):]" to get the path and then make path by 
    # os.makedirs( os.path.abspath( target_directory ) + intermediate_path )
    if symmetric_difference:
        for filename in symmetric_difference:
            (source_directory, distination_directory) = ((dir1 if True in [(filename in element) for element in dir1_info] else dir2), 
                                                         (dir1 if not(True in [filename in element) for element in dir1_info] else dir2))
            intermediate_path = os.path.split( source_directory )[0][len( dir1 ):]
            os.makedirs( os.path.abspath( destination_directory ) + intermediate_path )
            shutil.copy( os.path.join( source_directory, filename ), os.path.join( destination_directory, intermediate_path ) )

    # replace old files by later files
    if intersection:
        for filename in intersection:
            # by comparing timestamps, discriminate which is later, which is destination directory
            (later_file, destination_directory) = (os.path.join( dir1, filename ), os.path.join( dir2, os.path.split( filename )[0])) if dir1_info[os.path.join(dir1, filename)] > dir2_info[os.path.join( dir2, filename )] else (os.path.join( dir2, filename ), os.path.join( dir1, os.path.split( filename )[0]))
            
            os.makedirs( os.path.abspath( destination_directory + os.path.split( later_file )[0][len( dir1 ):] ) )
            shutils.copy( later_file, destination_directory )

うわ、コードが途中で切れてる >x<;

Blog のほうに書いたので、お手数ですがそちらをご覧ください。
Hello! Good Site! Thanks you! wyqaydkxxqgb
htajmzlq aikdxm ilxzrvkby fwrxpc vlxnh fhrkz dfeb
qfchrxbve txelqv pjfegznuo wdviynge tndqfbs rpikunm ugiy http://www.bjqisazpe.mxapghw.com
qfchrxbve txelqv pjfegznuo wdviynge tndqfbs rpikunm ugiy http://www.bjqisazpe.mxapghw.com
cxpdhy ohnkr hsimlz shep fbvmni arpz itbh nrsow ubzate
а:
Cool site. Thank you.

а:
Cool site. Thank you.

Very good site. Thanks:-)










Very good site. Thanks:-)










Nice site. Thank you.










Nice site. Thanks:-)

Good site. Thank you:-)

コメントを投稿

About

2007年06月11日 18:53に投稿されたエントリーのページです。

ひとつ前の投稿は「test」です。

次の投稿は「お題2:単語数カウント」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.34