Показать полную графическую версию : Копирование файла из одной папки в другую в определенные интервалы времени (bat)
pinguindell
06-08-2019, 15:48
Добрый день уважаемые форумчане
Знаю, что такую задачу можно реализовать, с помощью bat файла, но не знаю как его написать, поэтому обращаюсь к Вам за помощью
Есть папки :
Откуда : T:\Откуда
Куда : C:\Users\UserName\Desktop\Куда
Необходимо чтобы bat файл, в 09 :00, в 12:00 и в 17:00, делал копию файла Презентация.pptx, который находится в папке Откуда и помещал его в папку Куда, при этом архивировал его в zip архив. Название архива должно состоять из названия копируемого файла, в нашем случае, это Презентация и даты и времени копирования.
Например Презентация_дата копирования_время копирования
Буду признателен за Вашу помощь
pinguindell, в пакетных файлах нет встроенных средств для создания архивов. Посему лучшим вариантом из встроенных средств будет использование PowerShell, наподобие:
Add-Type -AssemblyName 'System.IO.Compression.FileSystem'
$sFileName = 'Презентация.pptx'
$sSourceFolder = 'T:\Откуда'
$sDestFolder = [System.IO.Path]::Combine([System.Environment]::GetFolderPath('Desktop'), 'Куда')
$sSourceFileName = [System.IO.Path]::Combine($sSourceFolder, $sFileName)
$sDestFileName = [System.IO.Path]::Combine($sDestFolder, [System.IO.Path]::GetFileNameWithoutExtension($sFileName) + (Get-Date -f '_yyyyMMdd_HHmmss') + '.zip')
if([System.IO.File]::Exists($sSourceFileName)) {
if([System.IO.Directory]::Exists($sDestFolder)) {
Compress-Archive -Path $sSourceFileName -DestinationPath $sDestFileName -Force
if([System.IO.File]::Exists($sDestFileName)) {
Write-Host "Successfully create zip-archive [$sDestFileName]." -ForegroundColor Green
} else {
Write-Host "Can't create zip-archive [$sDestFileName]." -ForegroundColor Red
}
} else {
Write-Host "Can't find destination folder [$sDestFolder]." -ForegroundColor Red
}
} else {
Write-Host "Can't find source file [$sSourceFileName]." -ForegroundColor Red
}
в 09 :00, в 12:00 и в 17:00, »
Создаёте задание в Планировщике, которое будет исполнять скрипт PowerShell с данным кодом в указанное время.
megaloman
06-08-2019, 17:16
pinguindell, Посредством бесплатного архиватора 7Z (имя файла и путь укажите свои,
при наличии в именах файла/папок кириллицы озаботьтесь сохранить скрипт в 866 кодировке) @Echo Off
Set "FileIn=Z:\Box_In\Вязкость.png"
Set "BoxArc=Z:\Box_Arc"
Call :Arc "%FileIn%" "%BoxArc%"
Exit /B
:Arc
If Not Exist %1 (Echo File %1 not found &Exit /B 2)
If Not Exist "%~2\" (Echo Folder %2 not found &Exit /B 2)
FOR /F "tokens=2 delims==." %%d in ('WMIC OS GET LOCALDATETIME /VALUE') DO (
"C:\Program Files\7-Zip\7z.exe" a "%~2\%~n1_%%d.zip" %1 -mx5
)
Exit /BСоздаёте задание в Планировщике, которое будет исполнять скрипт с данным кодом в указанное время. »
pinguindell
07-08-2019, 08:55
Iska, спасибо большое !
и еще небольшое дополнение, для запуска power shell скрипта через планировщик, без отображения окна PowerShell, написал скрипт vbs, который запускает все это великолепие в фоновом режиме, без показа окна консоли
command = "powershell.exe -nologo -noninteractive -command C:\Users\user_name\Desktop\ps_script.ps1"
set shell = CreateObject("WScript.Shell")
shell.Run command,0, false
плюс в самой задаче в планировщике, во вкладке Общие, установить галку внизу "Скрытая задача"
megaloman , также спасибо большое, буду изучать и Ваш вариант
megaloman
07-08-2019, 11:01
написал скрипт vbs, который запускает все это великолепие в фоновом режиме, без показа окна консоли »Ну, раз такая пьянка, то лучше уж всё сделать в VBS. Нагуглил, доработал. FileIn = "Z:\Box_In\Вязкость.png"
BoxArc = "Z:\Box_Arc"
With CreateObject("Scripting.FileSystemObject")
If Not .FileExists(FileIn) Then
WScript.Echo "!!! File " + FileIn + " not found"
WScript.Quit 1
End If
If Not .FolderExists(BoxArc) Then
WScript.Echo "!!! Folder " + BoxArc + " not found"
WScript.Quit 1
End If
DT = CStr(Year(Date)) + Right("0" + CStr(Month(Date)), 2) + Right("0" + CStr(Day(Date)), 2)
DT = DT + Right("0" + CStr(Hour(Time)), 2) + Right("0" + CStr(Minute(Time)), 2) + Right("0" + CStr(Second(Time)), 2)
Zip = BoxArc + "\" + .GetBaseName(FileIn) + "_" + DT + ".zip"
On Error Resume Next
Err.Number = 0
.CreateTextFile(Zip, True).Write "PK" + Chr(5) + Chr(6) + String(18, vbNullChar)
If Err.Number <> 0 Then
WScript.Echo "!!! " + Zip + " " + Err.Description + "(" + CStr(Err.Number) + ")"
WScript.Quit 1
End If
Set App = CreateObject("Shell.Application")
Err.Number = 0
App.Namespace(Zip).CopyHere FileIn
If Err.Number <> 0 Then
WScript.Echo "!!! " + Zip + " " + Err.Description + "(" + CStr(Err.Number) + ")"
WScript.Quit 1
End If
End With
On Error GoTo 0
WScript.Echo "=== " + Zip + " Done"
Оказывается, нечто подобное было на форуме. (http://forum.oszone.net/thread-266361.html) При большом объеме будет окно ожидания.
App.Namespace(Zip).CopyHere (FileIn) »
Полагаю, эти скобки — лишние.
megaloman
07-08-2019, 16:43
Iska, Скобки там не существенны, хотя лишнее - всегда во вред. Хуже, что скрипт работает корректно только при запуске посредством Wscript, с Cscript писАть в архив не хочет.
Iska, Скобки там не существенны, »
megaloman, согласен.
Собственно, всю разницу можно увидеть на таком примере:
Option Explicit
Dim strValue
strValue = "AAAA"
SomeSub strValue
WScript.Echo "strValue = " & strValue
WScript.Echo
strValue = "AAAA"
SomeSub (strValue)
WScript.Echo "strValue = " & strValue
WScript.Quit 0
Sub SomeSub(anyValue)
WScript.Echo "anyValue before = " & anyValue
anyValue = anyValue & "+" & anyValue
WScript.Echo "anyValue after = " & anyValue
End Sub
anyValue before = AAAA
anyValue after = AAAA+AAAA
strValue = AAAA+AAAA
anyValue before = AAAA
anyValue after = AAAA+AAAA
strValue = AAAA
По умолчанию, в VBScript параметры передаются по ссылке (в стек кладётся не значение переменной-параметра, а ссылка на саму переменную-параметр), посему, если изменить значение аргумента внутри процедуры/функции — это отразится на значении самого переданного параметра (поскольку на самом деле работа идёт как раз с ним).
Когда аргумент заключается в скобки — тем самым сначала вычисляется выражение в скобках, а затем уже это вычисленное значение передаётся в процедуру/функцию.
В таких языках, как, например, AutoIt — там практически любой вызов оформляется скобками, а вот в VBScript — скобки используются только тогда, когда вызов осуществляется в правой части выражения. В противном случае скобки интерпретируются не как скобки при вызове процедуры/функции, а как необходимость вычисления выражения.
Когда у нас имеется несколько параметров — ничего страшного, попытка такого вызова:
SomeSub (strValue1, strValue2)
приведёт к тому, что возникнет ошибка компиляции «Недопустимо использование скобок при вызове процедуры Sub». А вот если аргумент будет один, как в случае выше:
SomeSub (strValue)
— компилятор просто решит, что «ничего страшного, (strValue) — это просто выражение, которое надо вычислить и затем передать его значение в процедуру/функцию».
Хуже, что скрипт работает корректно только при запуске посредством Wscript, с Cscript писАть в архив не хочет. »
И хочет, и пишет. Просто не успевает, поскольку метод .CopyHere() работает асинхронно, т.е., объект Folder класса Shell.Application не ждёт окончания работы метода, а сразу возвращает управление скрипту, который, соответственно, продолжает свою работу. Боюсь, что на достаточно крупных файлах «обломится» и wscript.exe (сейчас не проверялось, я уже не помню конкретики).
megaloman
07-08-2019, 18:35
Iska, wscript.exe 1,4G съедает без проблем, сscript.exe и с 3 байтами не справляется. Но если вставить sleep (у меня 30 сек) ............
Set App = CreateObject("Shell.Application")
Call App.Namespace(Zip).CopyHere(FileIn)
WScript.Sleep 30 * 1000
If Err.Number <> 0 Then
............
то мой ноут времён куликовской битвы при запуске скрипта с cscript справляется с 190М
megaloman, посмотрел. Дело совсем не в том, под каким хостом исполняется скрипт — wscript.exe/cscript.exe. Уберите завершающее:
WScript.Echo "=== " + Zip + " Done"
которое не даёт скрипту вовремя завершиться, и посмотрите на получившийся результат :).
Повторяю, метод .CopyHere() работает асинхронно с поздним связыванием VBScript, посему — увы и ах :(.
megaloman
07-08-2019, 19:08
Iska, посмотрите на получившийся результат » Посмотрел, если не дать поспать в cscript, в архив не пишется, wscript справляется, правда, последнее Echo нужно. Но тогда решение не годится для планировщика
если не дать поспать, в архив не пишется. »
Да, и в этом главная проблема: паузу-то любой длительности сделать можно, а вот как определить момент, когда данный асинхронный метод закончит исполняться?! Особенно, когда нам нужно добавить в архив не один-единственный файл, а целую кучу файлов и папок с разных исходных мест, к примеру. Есть, конечно, обходные пути, но всё это настолько ненадёжно и нестабильно…
megaloman
07-08-2019, 19:21
Iska, В общем, корявство. Можно, конечно, сделать долгий слип, заведомо достаточный для конкретной задачи.
megaloman
08-08-2019, 11:46
Iska, pinguindell, Для себя делаю резюме:
FileIn = "Z:\Box_In\С Днем Рождения.ppt"
BoxArc = "Z:\Box_Arc"
With CreateObject("Scripting.FileSystemObject")
If Not .FileExists(FileIn) Then
WScript.Echo "!!! File " + FileIn + " not found"
WScript.Quit 1
End If
If Not .FolderExists(BoxArc) Then
WScript.Echo "!!! Folder " + BoxArc + " not found"
WScript.Quit 1
End If
DT = CStr(Year(Date)) + Right("0" + CStr(Month(Date)), 2) + Right("0" + CStr(Day(Date)), 2)
DT = DT + "-" + Right("0" + CStr(Hour(Time)), 2) + Right("0" + CStr(Minute(Time)), 2) + Right("0" + CStr(Second(Time)), 2)
Zip = BoxArc + "\" + .GetBaseName(FileIn) + "_" + DT + ".zip"
On Error Resume Next
Err.Number = 0
.CreateTextFile(Zip, True).Write "PK" + Chr(5) + Chr(6) + String(18, vbNullChar)
If Err.Number <> 0 Then
WScript.Echo "!!! " + Zip + " " + Err.Description + "(" + CStr(Err.Number) + ")"
WScript.Quit 1
End If
Err.Number = 0
Set App = CreateObject("Shell.Application")
Call App.Namespace(Zip).CopyHere(FileIn)
If Err.Number <> 0 Then
WScript.Echo "!!! " + Zip + " " + Err.Description + "(" + CStr(Err.Number) + ")"
WScript.Quit 1
End If
End With
On Error GoTo 0
MsgBox "После окончания процесса записи в архив нажмите ОК"
..............
..............
Call App.Namespace(Zip).CopyHere(FileIn)
WScript.Sleep 300 * 1000
If Err.Number <> 0 Then
WScript.Echo "!!! " + Zip + " " + Err.Description + "(" + CStr(Err.Number) + ")"
WScript.Quit 1
End If
End With
On Error GoTo 0
' MsgBox "После окончания процесса записи в архив нажмите ОК"
Можно, конечно, попробовать обойтись без Sleep Как вариант, посчитать количество файлов в архиве. Но это скользкий путь, так как при архивации большого файла он помещается в архив не сразу целиком, и преждевременное завершение скрипта приведёт к созданию увечного архива.
FileIn = "Z:\Box_In\С Днем Рождения.ppt"
BoxArc = "Z:\Box_Arc"
Arc = "C:\Program Files\7-Zip\7z.exe"
DT = CStr(Year(Date)) + Right("0" + CStr(Month(Date)), 2) + Right("0" + CStr(Day(Date)), 2)
DT = DT + "-" + Right("0" + CStr(Hour(Time)), 2) + Right("0" + CStr(Minute(Time)), 2) + Right("0" + CStr(Second(Time)), 2)
Zip = BoxArc + "\" + CreateObject("Scripting.FileSystemObject").GetBaseName(FileIn) + "_" + DT + ".zip"
Comm = """" + Arc + """ a """ + Zip + """ """ + FileIn + """ -mx5"
On Error Resume Next
R = CreateObject("WScript.Shell").Run(Comm, 0, False)
If Err.Number <> 0 Then
WScript.Echo "Ошибка при вызове архиватора." + vbCrLf + vbCrLf + Comm + vbCrLf + vbCrLf + "Проверьте наличие файлов по указанным путям" + vbCrLf + Err.Description + "(" + CStr(Err.Number) + ")"
WScript.Quit 1
End If
On Error GoTo 0
Поубирал почти все проверки на существование файлов, так как всё равно при исполнении в назначенных заданиях аварийные сообщения никто не увидит. Кстати, а не сделать ли лог-файл этого процесса?
megaloman
09-08-2019, 15:09
pinguindell, можно вообще обойтись без файла со сценарием в назначенных заданиях.mshta vbscript:execute("fRAR="" """"Z:\Box_Arc\С Днем Рождения.ppt_.zip"""""" : fIn="" """"Z:\Box_In\С Днем Рождения.ppt"""""" : RAR=""""""C:\Program Files\WinRAR\Rar.exe"""" a -ep -dh -agYYYYMMDD-HHMMSS"" : R=CreateObject(""WScript.Shell"").Run(RAR+fRAR+fIn, 0, False) :close")Но тут используется уже winrar c его возможностью добавлять к имени файла дату и время.
Serguei Kouzmine
11-08-2019, 22:03
*** let me Google that for you ***
$source_path = 'c:\Users\Serguei\Music\Folder with a ton of Music'
$destination_path = 'c:\temp'
$zip_filename = 'result'
$zip_path = "${destination_path}\${zip_filename}.zip"
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | out-null
# create empty zip magic
set-content $zip_path ( [byte[]] @( 80, 75, 5, 6 + (, 0 * 18 ) ) ) -encoding byte
$source_folder = ( new-object -com 'Shell.Application' ).NameSpace( $source_path )
$zip_folder = ( new-object -com 'Shell.Application' ).NameSpace( $zip_path )
# запускаем на выполнение в диалог прогресс режиме, конца выполнения не ждём.
$zip_folder.CopyHere( $source_folder, 16 )
$check_count = (get-childitem -path $source_path ).count
$done = $false
# вот теперь ждем по большому
while ($done -eq $false){
try{
$check_zip = [IO.Compression.ZipFile]::OpenRead($zip_path)
write-debug ('Counting items: {0}' -f ($check_zip.Entries).count )
if( ($check_zip.Entries).count -eq $check_count){
$check_zip.Dispose()
$done = $true
break
}
} catch [Exception] {
}
start-sleep -seconds 1
write-host '.' -nonewline
}
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.