Synchronize or merge two folders
tony
I haven't tested this extensively, caveat emptor!
Files in destination folder are overwritten by newer versions in source folder.
This could potentially be used for client-based synchronization of procedure files over a network.
// this is not a complete synchronization, files are not deleted from the
// destination folder if they don't exist in the source folder. So more
// of a sync-merge.
function SyncTest(int bothways)
NewPath/Q/O/M="Select Source Folder" pathSource
PathInfo pathSource
string source = s_path
NewPath/Q/O/M="Select Destination Folder" pathDestination
PathInfo pathDestination
string destination = s_path
string strOverwrites = SyncFolder(source, destination, test=1, bothways=bothways)
// check that we don't somehow what to move a file in both directions
if (CheckForError(source, destination, strOverwrites))
doAlert 0, "Unexpected sync error, quitting without copying anything"
return 0
endif
int numOverwrites = ItemsInList(strOverwrites)
if (numOverwrites)
DoAlert 1, num2str(numOverwrites) + " files will be overwritten.\r\rContinue?"
if (v_flag==2)
return 0
endif
endif
SyncFolder(source, destination, bothways=bothways)
end
// Merges folders like copyFolder on Windows
// Files in destination folder are overwritten by more recently modified
// files from source
// Setting test=1 doesn't copy anything but generates a list of files
// that would be overwritten
// ignore is a string list of names of files that should not be copied.
// set bothways=1 for bidirectional synchonization
// Recommended to run with test=1 to check for problems before trying to sync!
function/S SyncFolder(source, destination, [backupPathStr, test, ignore, bothways])
string source, destination
int test
string backupPathStr // must be no more than one sublevel below an existing folder
string ignore // list of filenames that won't be copied
int bothways
test = ParamIsDefault(test) ? 0 : test
backupPathStr = SelectString(ParamIsDefault(backupPathStr), backupPathStr, "")
ignore = SelectString(ParamIsDefault(ignore), ignore, "")
int backup = (strlen(backupPathStr) > 0)
bothways = ParamIsDefault(bothways) ? 0 : bothways
// clean up paths
source = ParseFilePath(2, source, ":", 0, 0)
destination = ParseFilePath(2, destination, ":", 0, 0)
if (backup)
backupPathStr = ParseFilePath(2, backupPathStr, ":", 0, 0)
endif
// check that source and destination folders exist
GetFileFolderInfo/Q/Z source
int sourceOK = V_isFolder
GetFileFolderInfo/Q/Z destination
if (sourceOK==0 || V_isFolder==0)
return ""
endif
int folderIndex, fileIndex, subfolderIndex
int folderCount = 1, sublevels = 0
string folderList, fileList, fileName
string copiedFileList = "", subPathStr = ""
string destFolderStr = "", sourceFolderStr = "", backupFolderStr = ""
variable sourceMod
int filefound
Make/free/T/N=0 w_folders, w_subfolders
w_folders = {source}
do
// step through folders at current sublevel
for (folderIndex=0;folderIndex<numpnts(w_folders);folderIndex+=1)
// figure out destination folder to match current source folder
sourceFolderStr = w_folders[folderIndex]
subPathStr = (sourceFolderStr)[strlen(source),strlen(sourceFolderStr)-1]
destFolderStr = destination + subPathStr
backupFolderStr = backupPathStr + subPathStr
// make sure that folder exists at destination
if (test == 0)
NewPath/C/O/Q/Z tempPathSync, destFolderStr
if (backup)
NewPath/C/O/Q/Z tempPathSync, backupFolderStr
endif
endif
// get list of source files in indexth folder at current sublevel
NewPath/O/Q/Z tempPathSync, sourceFolderStr
fileList = IndexedFile(tempPathSync, -1, "????")
// remove files from list if they match an entry in ignorefileList
fileList = RemoveFromListWC(fileList, ignore)
// copy files
for (fileIndex=0;fileIndex<ItemsInList(fileList);fileIndex+=1)
fileName = StringFromList(fileIndex, fileList)
GetFileFolderInfo/Q/Z sourceFolderStr + fileName
sourceMod = V_modificationDate // store source file modification date
GetFileFolderInfo/Q/Z destFolderStr + fileName
filefound = (v_flag == 0) && v_isFile
// allow for 10s difference in modification time in case
// different file systems don't match modification times
// precisely.
// this may have to be rethought if problems arise.
sourceMod = filefound ? V_modificationDate < (sourceMod-10) : 1
// sourceMod = 1 for file to be copied
if (test)
if (filefound && sourceMod) // file is to be overwritten
copiedFileList = AddListItem(destFolderStr + fileName, copiedFileList)
endif
else
if (backup) // back up any files that are to be overwritten
if (filefound && sourceMod) // file is to be overwritten
CopyFile/Z/O destFolderStr + fileName as backupFolderStr + fileName
endif
endif
if (sourceMod)
CopyFile/Z/O sourceFolderStr + fileName as destFolderStr + fileName
copiedFileList = AddListItem(destFolderStr + fileName, copiedFileList)
endif
endif
endfor
// make a list of subfolders in current folder
folderList = IndexedDir(tempPathSync, -1, 0)
// add the list of folders to the subfolders wave
for (subfolderIndex=0;subfolderIndex<ItemsInList(folderList);subfolderIndex+=1)
w_subfolders[numpnts(w_subfolders)] = {sourceFolderStr + StringFromList(subfolderIndex, folderList) + ":"}
folderCount += 1
endfor
endfor
// prepare for next sublevel iteration
Duplicate/T/O/free w_subfolders, w_folders
Redimension/N=0 w_subfolders
sublevels += 1
if (numpnts(w_folders) == 0)
break
endif
while(1)
KillPath/Z tempPathSync
if (bothways)
copiedFileList += SyncFolder(destination, source, backupPathStr=backupPathStr, test=test, ignore=ignore, bothways=0)
endif
return SortList(copiedFileList)
end
// returns listStr, purged of any items that match an item in ZapListStr.
// Wildcards okay! Case insensitive.
function/S RemoveFromListWC(string listStr, string zapListStr)
string removeStr = ""
int i
for (i=ItemsInList(zapListStr)-1;i>=0;i-=1)
removeStr += ListMatch(listStr, StringFromList(i, zapListStr))
endfor
return RemoveFromList(removeStr, listStr, ";", 0)
end
function CheckForError(string source, string destination, string strFileList)
if (ItemsInList(strFileList) == 0)
return 0
endif
wave/T wText = ListToTextWave(strFileList, ";")
wText = RemoveStart(wText, source)
wText = RemoveStart(wText, destination)
FindDuplicates/Z/free/DT=dupsWave wText
return numpnts(dupsWave)
end
function/S RemoveStart(string str, string startingStr)
int len = strlen(startingStr)
if (len == 0)
return str
endif
if (cmpstr(startingStr, str[0,len-1]) == 0)
return str[len,Inf]
endif
return str
end
// destination folder if they don't exist in the source folder. So more
// of a sync-merge.
function SyncTest(int bothways)
NewPath/Q/O/M="Select Source Folder" pathSource
PathInfo pathSource
string source = s_path
NewPath/Q/O/M="Select Destination Folder" pathDestination
PathInfo pathDestination
string destination = s_path
string strOverwrites = SyncFolder(source, destination, test=1, bothways=bothways)
// check that we don't somehow what to move a file in both directions
if (CheckForError(source, destination, strOverwrites))
doAlert 0, "Unexpected sync error, quitting without copying anything"
return 0
endif
int numOverwrites = ItemsInList(strOverwrites)
if (numOverwrites)
DoAlert 1, num2str(numOverwrites) + " files will be overwritten.\r\rContinue?"
if (v_flag==2)
return 0
endif
endif
SyncFolder(source, destination, bothways=bothways)
end
// Merges folders like copyFolder on Windows
// Files in destination folder are overwritten by more recently modified
// files from source
// Setting test=1 doesn't copy anything but generates a list of files
// that would be overwritten
// ignore is a string list of names of files that should not be copied.
// set bothways=1 for bidirectional synchonization
// Recommended to run with test=1 to check for problems before trying to sync!
function/S SyncFolder(source, destination, [backupPathStr, test, ignore, bothways])
string source, destination
int test
string backupPathStr // must be no more than one sublevel below an existing folder
string ignore // list of filenames that won't be copied
int bothways
test = ParamIsDefault(test) ? 0 : test
backupPathStr = SelectString(ParamIsDefault(backupPathStr), backupPathStr, "")
ignore = SelectString(ParamIsDefault(ignore), ignore, "")
int backup = (strlen(backupPathStr) > 0)
bothways = ParamIsDefault(bothways) ? 0 : bothways
// clean up paths
source = ParseFilePath(2, source, ":", 0, 0)
destination = ParseFilePath(2, destination, ":", 0, 0)
if (backup)
backupPathStr = ParseFilePath(2, backupPathStr, ":", 0, 0)
endif
// check that source and destination folders exist
GetFileFolderInfo/Q/Z source
int sourceOK = V_isFolder
GetFileFolderInfo/Q/Z destination
if (sourceOK==0 || V_isFolder==0)
return ""
endif
int folderIndex, fileIndex, subfolderIndex
int folderCount = 1, sublevels = 0
string folderList, fileList, fileName
string copiedFileList = "", subPathStr = ""
string destFolderStr = "", sourceFolderStr = "", backupFolderStr = ""
variable sourceMod
int filefound
Make/free/T/N=0 w_folders, w_subfolders
w_folders = {source}
do
// step through folders at current sublevel
for (folderIndex=0;folderIndex<numpnts(w_folders);folderIndex+=1)
// figure out destination folder to match current source folder
sourceFolderStr = w_folders[folderIndex]
subPathStr = (sourceFolderStr)[strlen(source),strlen(sourceFolderStr)-1]
destFolderStr = destination + subPathStr
backupFolderStr = backupPathStr + subPathStr
// make sure that folder exists at destination
if (test == 0)
NewPath/C/O/Q/Z tempPathSync, destFolderStr
if (backup)
NewPath/C/O/Q/Z tempPathSync, backupFolderStr
endif
endif
// get list of source files in indexth folder at current sublevel
NewPath/O/Q/Z tempPathSync, sourceFolderStr
fileList = IndexedFile(tempPathSync, -1, "????")
// remove files from list if they match an entry in ignorefileList
fileList = RemoveFromListWC(fileList, ignore)
// copy files
for (fileIndex=0;fileIndex<ItemsInList(fileList);fileIndex+=1)
fileName = StringFromList(fileIndex, fileList)
GetFileFolderInfo/Q/Z sourceFolderStr + fileName
sourceMod = V_modificationDate // store source file modification date
GetFileFolderInfo/Q/Z destFolderStr + fileName
filefound = (v_flag == 0) && v_isFile
// allow for 10s difference in modification time in case
// different file systems don't match modification times
// precisely.
// this may have to be rethought if problems arise.
sourceMod = filefound ? V_modificationDate < (sourceMod-10) : 1
// sourceMod = 1 for file to be copied
if (test)
if (filefound && sourceMod) // file is to be overwritten
copiedFileList = AddListItem(destFolderStr + fileName, copiedFileList)
endif
else
if (backup) // back up any files that are to be overwritten
if (filefound && sourceMod) // file is to be overwritten
CopyFile/Z/O destFolderStr + fileName as backupFolderStr + fileName
endif
endif
if (sourceMod)
CopyFile/Z/O sourceFolderStr + fileName as destFolderStr + fileName
copiedFileList = AddListItem(destFolderStr + fileName, copiedFileList)
endif
endif
endfor
// make a list of subfolders in current folder
folderList = IndexedDir(tempPathSync, -1, 0)
// add the list of folders to the subfolders wave
for (subfolderIndex=0;subfolderIndex<ItemsInList(folderList);subfolderIndex+=1)
w_subfolders[numpnts(w_subfolders)] = {sourceFolderStr + StringFromList(subfolderIndex, folderList) + ":"}
folderCount += 1
endfor
endfor
// prepare for next sublevel iteration
Duplicate/T/O/free w_subfolders, w_folders
Redimension/N=0 w_subfolders
sublevels += 1
if (numpnts(w_folders) == 0)
break
endif
while(1)
KillPath/Z tempPathSync
if (bothways)
copiedFileList += SyncFolder(destination, source, backupPathStr=backupPathStr, test=test, ignore=ignore, bothways=0)
endif
return SortList(copiedFileList)
end
// returns listStr, purged of any items that match an item in ZapListStr.
// Wildcards okay! Case insensitive.
function/S RemoveFromListWC(string listStr, string zapListStr)
string removeStr = ""
int i
for (i=ItemsInList(zapListStr)-1;i>=0;i-=1)
removeStr += ListMatch(listStr, StringFromList(i, zapListStr))
endfor
return RemoveFromList(removeStr, listStr, ";", 0)
end
function CheckForError(string source, string destination, string strFileList)
if (ItemsInList(strFileList) == 0)
return 0
endif
wave/T wText = ListToTextWave(strFileList, ";")
wText = RemoveStart(wText, source)
wText = RemoveStart(wText, destination)
FindDuplicates/Z/free/DT=dupsWave wText
return numpnts(dupsWave)
end
function/S RemoveStart(string str, string startingStr)
int len = strlen(startingStr)
if (len == 0)
return str
endif
if (cmpstr(startingStr, str[0,len-1]) == 0)
return str[len,Inf]
endif
return str
end
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More