Недавно делал подобную задачу - перемещение записей с камер в папки архива по датам, а также удаление старых в соответствии с лимитом веса архива.
Язык JScript. Предлагаю ознакомиться для начала:
/***********************************************************************************************************************
* avi_mover.js
* jite, 2010-11-24
*
* Переносит avi-файлы из папки записи sInFoldername в sNewPath\Камера\Дата\<ВремяС__ВремяПо>
* Ошибки исполнения пишет в лог sLogFilename
* Имеющиеся одноименные файлы перезаписывает (отмечает в логе)
*
* Положить скрипт рядом с папками камер "192.168.1..."
* Запускается без параметров - все переменные указываются в скрипте.
***********************************************************************************************************************/
var sInFoldername = "MotionRecordingFile"; // папка-скрипта\192.*\она-здесь
var sNewPath = "e:\\Cameras"; //Папка архива, без слэша на конце
var sLogFilename = "err_log.txt"; //Если имя без пути - лог пишется в папку со скриптом
var nMultipl = 1024 * 1024 * 1024; //Байт в гигабайте
//Ограничение общего веса файлов в папках sInFoldername и sArcFoldername, b * mult = GB
var nSizeLimit_def = 65 * nMultipl;
//Имя файла содержащего значение максимального допустимого веса файлов для 1 камеры
var sSizeLimitFilename = "SizeLimit.txt";
//Формат представления даты задается в sGetDateString()
//Формат представления времени - в sGetTimeString() и sGetTimeFromFile()
var sDL = "_"; //Разделитель
var sToday = sGetDateString(new Date()); //Сегодня - строкой
var oFS = new ActiveXObject("Scripting.FileSystemObject");
var sCamsfolderWithSlash = WScript.ScriptFullName.substr(0, WScript.ScriptFullName.length - WScript.ScriptName.length);
//sCamsfolderWithSlash = "D:\\00\\(Tmd)\\zcams_test\\"; //DEBUG
if (sLogFilename.indexOf("\\") == -1) //Если имя без пути
sLogFilename = sCamsfolderWithSlash + sLogFilename;
var oLog;
if (!oFS.FolderExists(sNewPath))
{
var sMsg = "Не найдено папки архива '" + sNewPath + "'";
WScript.Echo(sMsg);
LogWrite(sMsg);
WScript.Quit(2);
}
//Ищем папки камер
var reCamFolder = /^\d{3}\./gi;
var aCamFolders = aGetArrayOfFiles(oFS.GetFolder(sCamsfolderWithSlash), reCamFolder, false, true);
if (aCamFolders.length == 0)
{
var sMsg = "Не найдено ни одной папки с видеозаписями!";
WScript.Echo(sMsg);
LogWrite(sMsg);
WScript.Quit(2);
}
//--- 1) Перенос файлов из sInFoldername в sArcFoldername
//Для каждой камеры
for ( var i = 0; i < aCamFolders.length; i++) //Для записей каждой камеры
{
var sCamFolder_In = aCamFolders[i].Path + "\\" + sInFoldername;
var sCamFolder_Arc = sNewPath + "\\" + aCamFolders[i].Name;
//При отсутствии исходной папки записей - пропускаем камеру, с записью в лог
if (!bProvideFolder(sCamFolder_In, false, "записей"))
continue;
var oCamFolder_In = oFS.GetFolder(sCamFolder_In);
//При невозможности создать архивную - пропускаем камеру, с записью в лог
if (!bProvideFolder(sCamFolder_Arc, true, "архива записей"))
continue;
var oCamFolder_Arc = oFS.GetFolder(sCamFolder_Arc);
//Собираем файлы в папке
var reAviFile = /\.avi$/gi;
var aFiles = aGetArrayOfFiles(oCamFolder_In, reAviFile, true, false);
var oRecords = new Object();
//Отбираем подходящие на перемещение
for ( var j = 0; j < aFiles.length; j++)
{
var sFileDate = sGetDateString(aFiles[j].DateLastModified);
if (sFileDate !== sToday)
Collect(oRecords, sFileDate, aFiles[j]); //Если дата не равна сегодняшней, пишем в oRecords
}
if (oRecords.length == 0) //Перемещать нечего - пропускаем
continue;
for ( var sDate in oRecords)
{
var sDstFolder = oCamFolder_Arc.Path + "\\" + sDate;
if (!bProvideFolder(sDstFolder, true, "архива записей"))
continue;
for ( var k = 0; k < oRecords[sDate].length; k++)
{
var sNewFilename = sGetTimeFromFile(oRecords[sDate][k].Name);
try
{
if (sNewFilename !== "") //Если правильно вычленили время начала, добавляем разделитель
sNewFilename += sDL + sDL;
else
LogWrite("Неожиданное имя файла: '" + oRecords[sDate][k].Path + "'");
sNewFilename = sDstFolder + "\\" + sNewFilename + sGetTimeString(oRecords[sDate][k].DateLastModified) + ".avi";
if (oFS.FileExists(sNewFilename)) //Если нашли с таким же именем
{
LogWrite("Замена имеющегося файла '" + sNewFilename + "'");
oFS.DeleteFile(sNewFilename, true);
}
oRecords[sDate][k].Move(sNewFilename);
}
catch(e)
{
LogWrite("Ошибка переноса файла '" + oRecords[sDate][k].Path + "' в папку '" + sDstFolder + "' " + e.number +
": " + e.message);
}
} //Для каждого файла
} //Для каждой даты
} //Для каждой камеры
//--- 2) Удаление папок из sArcFoldername для обеспечения общего веса не более установленного
//Для каждой камеры
for ( var i = 0; i < aCamFolders.length; i++) //Для записей каждой камеры
{
var nSizeLimit = nSizeLimit_def; //default
var sSizeLimitFile = aCamFolders[i].Path + "\\" + sSizeLimitFilename;
var nRes = nGetSizeLimit(sSizeLimitFile, oFS);
if (nRes > 0)
nSizeLimit = nRes * nMultipl;
var sCamFolder_In = aCamFolders[i].Path + "\\" + sInFoldername; //Текущая папка записи
if (!oFS.FolderExists(sCamFolder_In)) //Папки нет
continue; //Не сообщаем, т.к. о возможных проблемах сообщалось в ч1
var oCamFolder_In = oFS.GetFolder(sCamFolder_In);
var oFD_In = oGetFD(oCamFolder_In); //Добыто
var sCamFolder_Arc = sNewPath + "\\" + aCamFolders[i].Name; //Текущая архивная
if (!bProvideFolder(sCamFolder_Arc, true, "архива записей")) //Не создалась? - пропускаем камеру и пишем в лог
continue;
var oCamFolder_Arc = oFS.GetFolder(sCamFolder_Arc);
var aArcFolders = aGetArrayOfFiles(oCamFolder_Arc, reGetDateRE(), false, true);
var aFD_Arc = new Array();
for ( var j = 0; j < aArcFolders.length; j++)
aFD_Arc.push(oGetFD(aArcFolders[j]));
aFD_Arc.sort(nSortFD);
//Подсчет размера до превышения разрешенного
var aFD_Delete = null; //Массив для удаления
var nSizeSum = oFD_In.Size;
if (nSizeSum > nSizeLimit) //Если записанного недавно так много, что архивы не влезают
aFD_Delete = aFD_Arc; //К удалению - все архивы
else
{ //Иначе проверяем объем архивов по объему
var nIdx = 0; //Индекс, начиная с которого все папки в aFD_Arc следует удалить, т.к. не влезают в лимиты
while (nIdx < aFD_Arc.length)
{
nSizeSum += aFD_Arc[nIdx].Size;
if (nSizeSum > nSizeLimit)
{
aFD_Delete = aFD_Arc.slice(nIdx); //Кусок массива, начиная с индекса nIdx
break;
}
nIdx++;
}
}
if (aFD_Delete !== null) //Если есть что удалять
{
for ( var j = 0; j < aFD_Delete.length; j++)
{
try
{
aFD_Delete[j].Link.Delete(true);
}
catch(e)
{
LogWrite("Ошибка удаления папки '" + aFD_Delete[j].Link.Path + "' " + e.number + ": " + e.message);
}
}
} //Есть что удалять
} //Для каждой камеры
//=== functions ========================================================================================================
/** Пишет в лог oLog сообщение sMsg, открывает лог если он еще не открыт
*/
function LogWrite(sMsg)
{
if (typeof (oLog) == "undefined") //Если не открыт, открываем (oLog - глобальная переменная)
{
oLog = new Log(sLogFilename);
if (oLog.nError !== 0)
{
WScript.Echo("Не удалось открыть лог. " + oLog.sLogName + " " + oLog.nError + " " + oLog.sErrorMsg);
WScript.Quit(1);
}
} //Если не открыт, открываем
oLog.WriteLine(sMsg);
}
/** Возвращает массив папок/файлов в папке oFolder (в подпапках не ищет)
* @param oFolder - FileSystemObject
* @param reNameMask - RegExp соответствия имени файла/папки (включая расширение) для включения в результаты поиска
* @param bGetFiles, bGetFolders - включать ли в результаты поиска имена файлов, папок, соответственно
* @return - FileSystemObject
*/
function aGetArrayOfFiles(oFolder, reNameMask, bGetFiles, bGetFolders)
{
var aOut = new Array();
var enFiles;
if (bGetFolders) //Собираем папки
{
enFiles = new Enumerator(oFolder.SubFolders);
Work(enFiles);
}
if (bGetFiles) //Собираем файлы
{
enFiles = new Enumerator(oFolder.Files);
Work(enFiles);
}
//Общий код
function Work(oEnum)
{
for (; !oEnum.atEnd(); oEnum.moveNext())
{
if (reNameMask.test(oEnum.item().Name))
aOut.push(oEnum.item());
reNameMask.test(""); //FIXED Лишний вызов, убирающий глюк возвращения неправильного false после true
}
}
return aOut;
}
/** Обеспечивает или только проверяет наличие папки sFolderName, при неудаче возвращает false
* @param sFullFolderName - полный путь к папке
* @param bDoCreate - пытаться ли создать папку?
* @param sErrMsg - сообщение в лог при неудаче
* @return boolean - Есть ли в результате папка?
*/
function bProvideFolder(sFullFolderName, bDoCreate, sErrMsgPart)
{
if (!oFS.FolderExists(sFullFolderName)) //Если не нашли - пишем в лог и - false
if (bDoCreate) //Попытаемся создать
{
try
{
oFS.CreateFolder(sFullFolderName);
}
catch(e)
{
LogWrite("Ошибка создания папки '" + sFullFolderName + "' " + e.number + ": " + e.message);
}
if (oFS.FolderExists(sFullFolderName))
return true;
else
{
LogWrite("Не удалось создать папку " + sErrMsgPart + " '" + sFullFolderName + "'");
return false;
}
}
else
{ //Не пытаемся создать
LogWrite("Папка " + sErrMsgPart + " '" + sFullFolderName + "' не найдена.");
return false;
}
else
return true;
}
/** Возвращает строкой определенного формата дату dDate.
*/
function sGetDateString(dDate)
{
var sWeekDays = ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"];
dDate = new Date(dDate); //FIXED Не признает переданную в функцию дату - датой. Убеждаем в обратном :)
return sLeadingZeros(dDate.getDate()) + "." + sLeadingZeros(dDate.getMonth() + 1) + "." + dDate.getFullYear() + sDL
+ sWeekDays[dDate.getDay()]; //ДД.ММ.ГГГГ_ДН
}
/** Возвращает регулярное выражение для поиска строк, выдаваемых sGetDateString()
* Вынесено в отдельную функцию для удобства совместной правки с sGetDateString()
*/
function reGetDateRE()
{
return /^(\d{2}\.){2}\d{2}.*$/gi;
}
/** Возвращает строкой формата hh-mm_ss дату dDate
*/
function sGetTimeString(dDate)
{
dDate = new Date(dDate); //FIXED Не признает переданную в функцию дату - датой. Убеждаем в обратном :)
return sLeadingZeros(dDate.getHours()) + "-" + sLeadingZeros(dDate.getMinutes()) + sDL +
sLeadingZeros(dDate.getSeconds()); //hh-mm_ss
}
/** Возвращает строкой формата hh-mm_ss время из имени файла
*/
function sGetTimeFromFile(sFilename)
{
var reFilenameAsDateStamp = /^\d{8}(\d{2})(\d{2})(\d{2})\.avi$/gi; //Исходное имя файла
var bRes = reFilenameAsDateStamp.test(sFilename);
reFilenameAsDateStamp.test(""); //FIXED Лишний вызов, убирающий глюк возвращения неправильного false после true
if (bRes)
return sFilename.replace(reFilenameAsDateStamp, "$1-$2_$3");
else
return "";
}
/** Дополняет текстовое представление obj (предполагается число) нулями до длины nOutLength. Минус выносится вперед
*/
function sLeadingZeros(obj, nOutLength)
{
if (typeof (obj) == "undefined")
return(null);
if (typeof (nOutLength) !== "number")
nOutLength = 2; //Выходная длина строки по ум.
var sObj = obj.toString(); //Строковое представление объекта
if (sObj.length < nOutLength) //Если надо удлинять
{
var res = "";
if (sObj.charAt(0) == "-") //Если отрицательное
{
res = "-";
sObj = sObj.substr(1);
}
var nZeros = nOutLength - res.length - sObj.length; //Число доп. нулей
for ( var i = 0; i < nZeros; i++)
res += "0";
res += sObj;
return(res);
}
else
//Удлинять не надо
return(sObj); //Возвращаем строковое представление
}
/** Добавляет в oBj значения oVal, используя sProp как свойства, каждое из которых содержит массив элементов oVal
*/
function Collect(oBj, sProp, oVal)
{
if (!(sProp in oBj))
oBj[sProp] = new Array();
oBj[sProp].push(oVal);
}
/** Возвращает число, содержащееся в 1-й строке файла sFilename. При неудаче возвращает 0
*/
function nGetSizeLimit(sFilename, oFS)
{
if (!oFS.FileExists(sFilename)) //Файла нет
return 0;
var oFile = oOpenForRead(sFilename, oFS);
if (oFile == null) //Не получилось открыть
return 0;
var sFirstLine = "";
try
{
sFirstLine = oFile.ReadLine();
var nOut = parseInt(sFirstLine, 10);
if (isNaN(nOut))
nOut = 0;
return nOut;
}
catch(e)
{
//WScript.Echo("Ошибка при чтении файла '" + sFilename + "': " + e.number + ": " + e.message);
return 0; //Нечего читать или не распознали
}
}
/** Открывает файл sFilename для чтения
*/
function oOpenForRead(sFilename, oFS)
{
var nForReading = 1;
var bCreate = false;
var oFile;
try
{
oFile = oFS.OpenTextFile(sFilename, nForReading, bCreate); //Открываем как ANSI
}
catch(e)
{
return null;
}
return oFile;
}
/** Возвращает данные папки sFolder в виде объекта FolderData. При неудаче - null
*/
function oGetFD(oFolder)
{
var aFiles = aGetArrayOfFiles(oFolder, /.+/gi, true, false);
var nSum = 0;
var dOldestFileDate = new Date(); //Дата старейшего файла в папке
for ( var j = 0; j < aFiles.length; j++)
{
var oParse = parseInt(aFiles[j].Size, 10);
if (!isNaN(oParse))
nSum += oParse;
else
LogWrite("oGetFD(). Подсчет веса. '" + aFiles[j].Path + "' Неожиданный размер файла '" + aFiles[j].Size + "'");
var dCurrentFileDate = aFiles[j].DateLastModified;
if (dCurrentFileDate < dOldestFileDate)
dOldestFileDate = dCurrentFileDate;
}
return new FolderData(oFolder, nSum, dOldestFileDate);
}
/** Класс данных о папке: oFS-ссылка и суммарный вес файлов в байтах (в подпапках не смотрит).
*/
function FolderData(oFolder, nSize, dDate)
{
this.Link = oFolder;
this.Size = nSize;
this.Date = dDate;
}
/** Функция для sort() массива элементов класса FolderData по дате (от новых к старым)
*/
function nSortFD(oBj1, oBj2)
{
return oBj2.Date - oBj1.Date;
}
/** Класс работы с логом -----------------------------------------------------------------------------------------------
* @param sFileName - имя файла лога
* @param bRewrite - перезаписывать или добавлять?
*/
function Log(sFileName, bRewrite)
{
this.sLogName = (sFileName.indexOf("\\") === -1) ? //Если не содержит слэшей (т.е. без пути)
//+ путь к папке скрипта
WScript.ScriptFullName.substring(0, WScript.ScriptFullName.length - WScript.ScriptName.length) + sFileName :
sFileName; //Иначе просто оставляем как есть
var oFS = new ActiveXObject("Scripting.FileSystemObject");
this.bCreateIfNotExist = true; //Создавать, если не существует
this.nOpenAs = 0; // 0 ascii, -1 unicode, -2 system default
this.nIOMode = 8; //По ум. дописывать лог
if (typeof (bRewrite) === "boolean" && bRewrite) //Если не опущено при вызове И true
this.nIOMode = 2; //Перезаписать лог
this.nError = 1;
this.sErrorMsg = "Лог еще не открыт";
// -2146823281 'undefined' - есть null или не является объектом --> попытка писать в не окрытый файл
// -2146828197 Объектная переменная или переменная блока With не задана --> попытка писать в закрытый файл
// -2146828218 Разрешение отклонено --> попытка открыть файл RO или с недостаточными правами доступа
try
{
this.oLog = oFS.OpenTextFile(this.sLogName, this.nIOMode, this.bCreateIfNotExist, this.nOpenAs);
this.nError = 0;
this.sErrorMsg = "";
}
catch(e)
{
this.nError = e.number;
this.sErrorMsg = e.message;
}
//--- Методы
this.Open = function()
{
try
{
this.oLog = oFS.OpenTextFile(this.sLogName, this.nIOMode, this.bCreateIfNotExist, this.nOpenAs);
this.nError = 0;
this.sErrorMsg = "";
}
catch(e)
{
this.nError = e.number;
this.sErrorMsg = e.message;
}
};
this.Write = function(sTr)
{
if (typeof (sTr) == "undefined")
sTr = "";
try
{
this.oLog.Write((new Date()).toLocaleString() + " " + sTr);
this.nError = 0;
this.sErrorMsg = "";
}
catch(e)
{
this.nError = e.number;
this.sErrorMsg = e.message;
}
};
this.WriteLine = function(sTr)
{
if (typeof (sTr) == "undefined")
sTr = "";
this.Write(sTr + "\r\n");
};
this.Close = function()
{
try
{
this.oLog.Close();
this.nError = 0;
this.sErrorMsg = "";
}
catch(e)
{
this.nError = e.number;
this.sErrorMsg = e.message;
}
};
} //Log()
//=== DEBUG_STUFF ======================================================================================================
/** Возвращает строку рекурсивного описания содержимого объекта oBj ----------------------------------------------------
* @param oBj - исследуемый объект
* @param sParentName - имя объекта, произвольное, по сути комментарий (можно опустить)
* @param nEsting - максимальный уровень вложенности объектов/значений (можно опустить)
*/
function vardump(oBj, sParentName, nEsting)
{
var nEsting_max = 20; //Максимальный исследуемый уровень вложенности
var nPadding = 2; //Структурный отступ в пробелах, сдвига потомков отн. родителей
if (typeof (sParentName) == "undefined") //default
sParentName = "";
if (typeof (nEsting) != "number") //default
nEsting = nEsting_max;
var sRes = "";
if (nEsting >= 0)
{
var nGap = nPadding * (nEsting_max - nEsting);
for ( var i = 0; i < nGap; i++)
sRes += " ";
sRes += sParentName + (sParentName == "" ? "" : " ") + "(" + typeof (oBj) + ")=>" + oBj + "<\r\n";
if (typeof (oBj) == "object")
for ( var oEl in oBj)
{
var sObjName = sParentName; //Имя потомка
if (sObjName != "") //Если есть что отделять, отделяем точкой
sObjName += ".";
sObjName += oEl;
sRes += arguments.callee(oBj[oEl], sObjName, nEsting - 1);
}
}
else
sRes = sParentName + " ! Nesting limit !\r\n";
return(sRes);
} //vardump
/**
* Echo-обертка для vardump()
*/
function vard()
{
WScript.Echo(vardump.apply(null, arguments));
}