Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » CMD/BAT - [решено] Случайный перебор по списку без повторения

Ответить
Настройки темы
CMD/BAT - [решено] Случайный перебор по списку без повторения

Старожил


Сообщения: 415
Благодарности: 257

Профиль | Отправить PM | Цитировать


Прошу помощи в оптимизации скрипта. Цель - выбрать все файлы из вложенных папок, подходящие под определённое условие (черный список\белый список) и запустить их в случайном порядке без повторений. В принципе задача довольно простая, и мною за десять минут был набросан приведённый ниже скрипт. Оттестировал на домашнем компьютере с папкой в пару сотен файлов, всё отлично работает. Но после запуска на довольно слабом по современным меркам компьютере и объеме файлов в ~16 тысяч столкнулся с заметными подвисаниями в пару десятков секунд перед переходом к следующему файлу. Собственно, проблема в функции :RebuildArray, которая каждый раз при запуске случайного файла, удаляет его из массива, генерируемого при старте скрипта. Думал над тем, как её ускорить - ничего не приходит в голову. Нужен именно батник, использование perl\python\чего-нибудь ещё - невозможно.

Код: Выделить весь код
@Echo Off
SetLocal EnableDelayedExpansion

::========Настройки========
:: Путь к рабочей директории, будут обработаны все файлы и поддиректории в ней
Set BasePath=D:\Video\MLP
:: Черный список - всё, что здесь перечислено, исключается из обработки.
:: Проверяются пути и имена файлов или их части, каждое значение должно быть заключено в кавычки.
Set BlackList=".ass" ".srt"
:: Белый список - действует аналогично черному списку, но в обработку попадает лишь перечисленное.
:: Белый список применяется ДО черного, но не отменяет его действие
Set WhiteList="Season_1" "Season_2" "Season_3"

:Main
:: Запуск в случайном порядке без повторений всех найденных файлов (ассоциированной с этим файлом программой)
Call :MakeArray||(Echo    ERROR: No files found&Exit /B 1)
For /L %%? In (1,1,%ArraySize%) Do (
	Call :GetRandomElement||(Echo    ERROR: No more files in the queue&Exit /B 1)
	Call Set "File=%%Array[!Selected!]%%"
	:: Вывод сообщения и запуск файла, переход на следующий после подтверждения
	CLS
	For /F "delims=" %%F In ("!File!") Do (
		Echo.
		Echo    Location: %%~dpF
		Echo    File: %%~nxF
		Echo.
	)
	Start "" "!File!"
	Echo    Press any key to next file [%%?/%ArraySize%]
	Pause>nul
	Call :RebuildArray
)
Exit /B

:MakeArray
:: Создаём массив из подходящих под условия файлов
Set ArraySize=0
:: Подготовка к работе черного и белого списков
For %%? In (Include Exclude) Do (Set %%?=)
For %%L In ("Include:WhiteList:/I" "Exclude:BlackList:/V /I") Do For /F "tokens=1-3 delims=:" %%A In ("%%~L") Do (
	If Not "!%%B!"=="" (
		For %%W In (!%%B!) Do (Set %%A=!%%A! /C:"%%~W")
		Set "%%A=|FindStr %%C!%%A!"
	)
)
:: Построение массива
For /F "delims=" %%F In ('Dir "!BasePath!" /A-D /B /S!Include!!Exclude!') Do (
	Set /A ArraySize+=1
	Set "Array[!ArraySize!]=%%F"
)
If "!ArraySize!"=="0" Exit /B 1
Exit /B

:GetRandomElement
:: Если в массиве не осталось элементов, кидаем ошибку
If %ArraySize% LEQ 0 Exit /B 1
:: Инициализируем ГПСЧ и получаем номер случайного элемента массива
Echo !Random!!Random!>nul
Set /A Selected=1+%ArraySize%*!Random!/32768
Exit /B

:RebuildArray
:: Пересобираем массив со сдвигом значений, исключая из него выбранный элемент
Set Array[%Selected%]=
For /L %%E In (%Selected%,1,%ArraySize%) Do (
	:: Проверка на конечный элемент массива
	If "%Selected%"=="%ArraySize%" (
		Set /A ArraySize-=1
		Exit /B
	)
	Set /A Next=%%E+1
	Call Set Array[%%E]=%%Array[!Next!]%%
)
Set /A ArraySize-=1
Exit /B

Отправлено: 10:42, 22-01-2014

 

Ветеран


Сообщения: 27449
Благодарности: 8086

Профиль | Отправить PM | Цитировать


Цитата Anonymоus:
Нужен именно батник, использование perl\python\чего-нибудь ещё - невозможно. »
А как насчёт WSH?

Отправлено: 11:06, 22-01-2014 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Старожил


Сообщения: 415
Благодарности: 257

Профиль | Отправить PM | Цитировать


Цитата Iska:
А как насчёт WSH? »
Вполне подойдёт, это же не сторонний интерпретатор.

Отправлено: 11:15, 22-01-2014 | #3


Ветеран


Сообщения: 27449
Благодарности: 8086

Профиль | Отправить PM | Цитировать


Anonymоus, пробуйте (требуется установленный .Net Framework):
читать дальше »
Код: Выделить весь код
Option Explicit

Const WshRunning  = 0
Const WshFinished = 1
Const WshFailed   = 2


Dim strSourceFolder
Dim arrBlackList
Dim arrWhiteList

Dim objFSO
Dim objWshShell

Dim strContent
Dim strLine

Dim objArrayList

Dim elem
Dim strKey

Dim objRandom
Dim intIndex


strSourceFolder = "D:\Video\MLP"

arrBlackList    = Array(".ass", ".srt")
arrWhiteList    = Array("Season_1", "Season_2", "Season_3")


Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")

If objFSO.FolderExists(strSourceFolder) Then
	Set objWshShell = WScript.CreateObject("WScript.Shell")
	
	With objWshShell.Exec("""%comspec%"" /c ""dir /a:-d /b /s """ & strSourceFolder & """""")
		If .Status <> WshFailed Then
			strContent = ""
			
			Do
				strContent = strContent & .StdOut.ReadAll()
			Loop Until .Status = WshFinished
		End If
	End With
	
	With WScript.CreateObject("System.Collections.ArrayList")
		For Each strLine In Split(strContent, vbCrLf)
			For Each elem In arrWhiteList
				If InStr(1, strLine, elem, vbTextCompare) > 0 Then
					If Not .Contains(strLine) Then
						.Add strLine
					End If
				End If
			Next
		Next
		
		For Each strKey In .Clone
			For Each elem In arrBlackList
				If InStr(1, strKey, elem, vbTextCompare) > 0 Then
					.Remove strKey
					
					Exit For
				End If
			Next
		Next
		
		Set objRandom = WScript.CreateObject("System.Random")
		
		Do While .Count > 0
			intIndex = objRandom.Next_2(0, .Count)
			
			MsgBox .Item(intIndex)
			objWshShell.Run """" & .Item(intIndex) & """", 1, True
			
			.RemoveAt intIndex
		Loop
		
		Set objRandom = Nothing
	End With
	
	Set objWshShell = Nothing
Else
	WScript.Echo "Source folder [" & strSourceFolder & "] not found."
	WScript.Quit 1
End If

Set objFSO = Nothing

WScript.Quit 0
Это сообщение посчитали полезным следующие участники:

Отправлено: 05:06, 26-01-2014 | #4


Старожил


Сообщения: 415
Благодарности: 257

Профиль | Отправить PM | Цитировать


Iska, благодарю за скрипт, протестировал на большом количестве файлов, по быстродействию намного быстрее батника. Правда, при тестировании всплыла проблема с кодировкой в путях с использованием кириллицы. На месседжбоксе перед запуском файла видно, что путь выглядит как "E:\HSA\„ў*з\2012\05\dump_ra.7z", соответственно после нажатия на "OK" получаю ошибку:
Код: Выделить весь код
Сценарий:	D:\Sandbox\random.vbs
Строка:	75
Символ:	4
Ошибка:	Не удается найти указанный файл. 
Код:	80070002
Источник: 	(null)

Отправлено: 14:23, 26-01-2014 | #5


Ветеран


Сообщения: 27449
Благодарности: 8086

Профиль | Отправить PM | Цитировать


Попробуйте так:
читать дальше »
Код: Выделить весь код
Option Explicit

Const WshRunning  = 0
Const WshFinished = 1
Const WshFailed   = 2

Dim strSourceFolder
Dim arrBlackList
Dim arrWhiteList


Dim objFSO
Dim objWshShell

Dim strContent
Dim strLine

Dim elem
Dim strKey

Dim objRandom
Dim intIndex


strSourceFolder = "D:\Video\MLP"

arrBlackList    = Array(".ass", ".srt")
arrWhiteList    = Array("Season_1", "Season_2", "Season_3")


Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")

If objFSO.FolderExists(strSourceFolder) Then
	Set objWshShell = WScript.CreateObject("WScript.Shell")
	
	With objWshShell.Exec("""%comspec%"" /c ""dir /a:-d /b /s """ & strSourceFolder & """""")
		If .Status <> WshFailed Then
			strContent = ""
			
			Do
				strContent = strContent & .StdOut.ReadAll()
			Loop Until .Status = WshFinished
		End If
	End With
	
	strContent = StrConvert(strContent, "windows-1251", "cp866")
	
	With WScript.CreateObject("System.Collections.ArrayList")
		For Each strLine In Split(strContent, vbCrLf)
			For Each elem In arrWhiteList
				If InStr(1, strLine, elem, vbTextCompare) > 0 Then
					If Not .Contains(strLine) Then
						.Add strLine
					End If
				End If
			Next
		Next
		
		For Each strKey In .Clone
			For Each elem In arrBlackList
				If InStr(1, strKey, elem, vbTextCompare) > 0 Then
					.Remove strKey
					
					Exit For
				End If
			Next
		Next
		
		Set objRandom = WScript.CreateObject("System.Random")
		
		Do While .Count > 0
			intIndex = objRandom.Next_2(0, .Count)
			
			MsgBox .Item(intIndex)
			objWshShell.Run """" & .Item(intIndex) & """", 1, True
			
			.RemoveAt intIndex
		Loop
		
		Set objRandom = Nothing
	End With
	
	Set objWshShell = Nothing
Else
	WScript.Echo "Source folder [" & strSourceFolder & "] not found."
	WScript.Quit 1
End If

Set objFSO = Nothing

WScript.Quit 0
'=============================================================================

'=============================================================================
' HKEY_CLASSES_ROOT\MIME\Database\Charset
' cp866, windows-1251, koi8-r, unicode, utf-8, _autodetect
'=============================================================================
Function StrConvert(ByVal strText, ByVal strSourceCharset, ByVal strDestCharset)
	Const adTypeText      = 2
	Const adModeReadWrite = 3
	
	
	With WScript.CreateObject("ADODB.Stream")
		.Type      = adTypeText
		.Mode      = adModeReadWrite
		
		.Open
		
		.Charset   = strSourceCharset
		.WriteText strText
		
		.Position  = 0
		.Charset   = strDestCharset
		StrConvert = .ReadText
		
		.Close
	End With
End Function
'=============================================================================
Это сообщение посчитали полезным следующие участники:

Отправлено: 15:57, 26-01-2014 | #6



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » CMD/BAT - [решено] Случайный перебор по списку без повторения

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
CMD/BAT - [решено] Перебор свободных IP по списку и выбор свободного Debugger Скриптовые языки администрирования Windows 4 11-02-2012 17:42
CMD/BAT - Перемещение файлов по списку Arsenik77 Скриптовые языки администрирования Windows 4 04-12-2011 20:43
Прочие БД - Извлечение файлов по списку Aviator Программирование и базы данных 1 22-02-2011 02:44
V. 5.5/2000/2003 - задача по списку рассылки Yampo Microsoft Exchange Server 14 18-03-2010 10:11
Перемещение по списку в Excel Evita Хочу все знать 3 16-03-2006 01:13




 
Переход