Что нового

редактирование файлов в зависимости от содержимого папок

Alexey

Новичок
AutoIT: 3.3.0.0
Описание: имеется очень много (обычных текстовых) файлов с расширением .cue (в разных папках и под-папках). более 2500 из них содержат сочетание из 5 символов: .wav"
при этом в папке с .cue всегда будет ещё файл с расширением .ape либо .flac либо .wv
нужно, чтобы скрипт заменял этот самый текстовый фрагмент .wav" на другой текстовый фрагмент: .ape" или .flac" или .wv", в зависимости от того, какой именно файл (ape, flac или wv) находится в этой же папке, где и файл .cue

Примечания: попытаюсь разъяснить максимально детально, что должно получиться:

1) в окно программы я перетаскиваю папку (в которой будет много под-папок, под-под-папок...)
2) программа проверяет каждую папку (под-папку...) на наличие в ней файла .cue (многие папки будут без .cue)
3) если файл .cue есть, то ищет в нём сочетание символов .wav" (оно будет не везде, а где будет, то лишь 1 раз, приблизительно в 6-7 строке)
4) если сочетание символов .wav" есть, то заменяет его на:
.ape" - если в этой же папке есть один (и не больше) файл .ape
.flac" - если в этой же папке есть один (и не больше) файл .flac
.wv" - если в этой же папке есть один (и не больше) файл .wv

в программе (и в программировании в общем) не разбираюсь совсем. решился попросить помочь, поскольку, во-первых, действительно нужно, а во-вторых - мне с AutoIT недавно очень помог sproxy (ник с другого форума), который, если я правильно понял, теперь здесь, и скрипт которого меня сильно выручает
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Вот так примерно:

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <File.au3>
;

$GUI = GUICreate("Test Script", 300, 200, -1, -1, -1, $WS_EX_ACCEPTFILES)

GUICtrlCreateLabel("Drop Folder here", 0, 0, 300, 200)
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
GUICtrlSetFont(-1, 16, 800)

GUISetState(@SW_SHOW, $GUI)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
		Case $GUI_EVENT_DROPPED
			$aFiles = _FileListToArrayEx(@GUI_DragFile, "*.*", -1)
			
			For $i = 1 To $aFiles[0]
				;Если это не файл .cue то продолжаем цикл далее
				If StringRight($aFiles[$i], 4) <> ".cue" Then ContinueLoop
				
				;Если в файле не найдено .wav то продолжаем цикл далее
				If Not StringInStr(FileRead($aFiles[$i]), ".wav") Then ContinueLoop
				
				;Получаем путь к текущей папке
				$sFolder = StringRegExpReplace($aFiles[$i], "\\[^\\]*$", "")
				
				$sReplace = ""
				
				;Проверяем существование файлов
				Select
					Case _FileGetFilesCount($sFolder, "*.ape") = 1
						$sReplace = ".ape"
					Case _FileGetFilesCount($sFolder, "*.flac") = 1
						$sReplace = ".flac"
					Case _FileGetFilesCount($sFolder, "*.wv") = 1
						$sReplace = ".wv"
					Case Else ;Ни один из нужных файлов не найден, продолжаем цикл далее
						ContinueLoop
				EndSelect
				
				_ReplaceStringInFile($aFiles[$i], ".wav", $sReplace)
			Next
	EndSwitch
WEnd

Func _FileGetFilesCount($sPath, $sMask)
	Local $aFiles = _FileListToArray($sPath, $sMask, 1)
	Return UBound($aFiles)-1
EndFunc

Func _FileListToArrayEx($sPath, $sMask="*", $iMode=-1) ;$iMode > 0 только папки (маска игнорируется), иначе папки + файлы
	If Not StringInStr(FileGetAttrib($sPath & "\"), "D") Then Return SetError(1, 0, 0)
	
	Local $hSearch, $sFindNext, $sFilePath, $iPathIsFolder, $i = 0
	Local $sRegExpFilter = StringReplace(StringReplace($sMask, ".", "\."), "*", ".*")
	Local $iMax_Ret_Paths = 10000
	Local $aPathesArr[$iMax_Ret_Paths+1] = [1, $sPath]
	
	While $i < $aPathesArr[0]
		$i += 1
		
		$hSearch = FileFindFirstFile($aPathesArr[$i] & "\*")
		If $hSearch = -1 Then ContinueLoop
		
		While 1
			$sFindNext = FileFindNextFile($hSearch)
			If @error Then ExitLoop
			
			$sFilePath = $aPathesArr[$i] & "\" & $sFindNext
			$iPathIsFolder = StringInStr(FileGetAttrib($sFilePath & "\"), "D")
			
			If $iMode <= 0 Or ($iMode > 0 And $iPathIsFolder) Then
				If $iPathIsFolder Or (Not $iPathIsFolder And StringRegExp($sFindNext, "(?i)" & $sRegExpFilter)) Then
					If $aPathesArr[0] >= $iMax_Ret_Paths Then
						$iMax_Ret_Paths *= 2
						ReDim $aPathesArr[$iMax_Ret_Paths+1]
					EndIf
					
					$aPathesArr[0] += 1
					$aPathesArr[$aPathesArr[0]] = $sFilePath
				EndIf
			EndIf
		WEnd
		
		FileClose($hSearch)
	Wend
	
	ReDim $aPathesArr[$aPathesArr[0]+1]
	Return $aPathesArr
EndFunc
 

amel27

Продвинутый
Alexey сказал(а):
4) если сочетание символов .wav" есть, то заменяет его на:
.ape" - если в этой же папке есть один (и не больше) файл .ape
.flac" - если в этой же папке есть один (и не больше) файл .flac
.wv" - если в этой же папке есть один (и не больше) файл .wv
гм... странная и весьма противоречивая постановка задачи, особенно учитывая спецификацию на формат Cue Sheet... по идее, требуется парсинг CUE файла на предмет треков, и работа с каждым файлом трека отдельно - проверка наличия альтернативных форматов и т.д.
 

Yashied

Модератор
Команда форума
Глобальный модератор
CreatoR сказал(а):
...если в этой же папке есть один (и не больше) файл .ape...
А если файлов .ape несколько? Такого не может быть?
 
Автор
A

Alexey

Новичок
CreatoR, спасибо огромное за отзывчивость. и за оперативность тоже

пока попробовал скрипт на примерно 10 разных папках, всё отредактировалось как надо

вот разве что:
А если файлов .ape несколько? Такого не может быть?
только сейчас попробовал. когда несколько ape - не работает.
я ещё подумаю, но вроде бы это не проблема, т.к. если файлов ape\flac\wv больше 1, то тогда в папке не должно быть cue

amel27,

не вполне уловил твою мысль. постановка задачи была такой, какой она мне была нужна. я учитываю в данном скрипте только ситуацию с image+cue, не потрэковый вариант (в котором у меня файлы cue отсутствуют). файлы cue с прописанными в них символами .wav нужны лишь один раз, да и то исключительно тем, кто записывает каждый альбом на болванки. я к таковым не отношусь. чтобы прослушивать с компа альбом в формате ape+cue / flac+cue / wv+cue необходимо, чтобы в cue была чётко прописана ссылка на ape\flac\wv. у меня сейчас 2532 cue-файла с неправильной ссылкой, что не позволяет проигрывать музыкальный файл по трэкам (!). а править вручную уже ни сил, ни нервов нет. и так более года этим занимался (а остальные десятки-сотни миллионов, слушающих музыку в lossless-качестве, и не знающих об этом скрипте, и дальше будут вынуждены извращаться)
 

amel27

Продвинутый
Alexey сказал(а):
остальные десятки-сотни миллионов, слушающих музыку в lossless-качестве, и не знающих об этом скрипте, и дальше будут вынуждены извращаться)
гм... если быстро и для себя, то в командной строке задача решается в несколько строк... но если для "миллионов", то ИМХО желательно делать по уму - т.е. с учетом ВСЕХ возможных вариантов и без риска нарушить формат файла... впрочем, хозяин - барин
:smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Alexey [?]
когда несколько ape - не работает.
В начале ведь было указано:
[?]
если в этой же папке есть один (и не больше)
Я с этого понял что выполнять нужно только если найдин один файл.
Для больше нужно заменить:

Код:
_FileGetFilesCount($sFolder, "*.ape") = 1
на
Код:
_FileGetFilesCount($sFolder, "*.ape") >= 1
 
Автор
A

Alexey

Новичок
2009.09.29 old message:

CreatoR, всё верно ты изначально понял, просто Yashied меня немножко с толку сбил, а главное - я сам не подумал сразу как следует :smile: мне нужно было ему просто ответить, что если файлов ape несколько, то это автоматически означает, что в папке с ними файла cue нет (это результат долгого разгребания муз. коллекции)
ведь действительно, если файлов ape больше 1, то это просто не подходит под условие задачи, а значит - игнорируется
ничего в скрипте менять не буду, он работает так как надо с первой же минуты (вот чего я точно не ожидал, так это того, что решение этой долгоиграющей проблемы будет найдено так быстро). если в поведении скрипта обнаружу что-либо не то, отпишусь обязательно. благодарю ещё раз

2009.12.03 update:

в связи с конвертированием нескольких тысяч ape и wv файлов во flac появилась необходимость, чтобы скрипт помимо замены в файлах .cue текстового фрагмента .wаv" (на .ape" или .flac" или .wv") ещё научился заменять:
текстовый фрагмент .ape" (на .flac") - в том случае, если в папке есть один (и не больше) файл .flac
текстовый фрагмент .wv" (на .flac") - в том случае, если в папке есть один (и не больше) файл .flac

не сразу, но получилось-таки достичь необходимого результата (действовал в значительной степени методом тыка и в меньшей - логикой, поскольку не разбираюсь в программировании). прошу CreatoR'а проверить правильность моих действий, чтобы точно знать, что нет никаких ошибок. в скрипте я добавил следующее:

1) строки с 21 по 46 были скопированы и дважды вставлены (в строки 48-73 и 75-100)
2) в строках 53, 72, 52 заменены .wav на .ape
3) в строках 80, 99, 79 заменены .wav на .wv

пока проверил на 25 папках при самых разных вариантах содержимого - всё работает

Код:
#include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <File.au3>
    ;
     
    $GUI = GUICreate("My Drag-Editor", 300, 200, -1, -1, -1, $WS_EX_ACCEPTFILES)
     
    GUICtrlCreateLabel("Drop Folder Here", 0, 0, 300, 200)
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    GUICtrlSetFont(-1, 16, 800)
     
    GUISetState(@SW_SHOW, $GUI)
     
    While 1
    	Switch GUIGetMsg()
    		Case $GUI_EVENT_CLOSE
    			Exit
    		Case $GUI_EVENT_DROPPED
    			$aFiles = _FileListToArrayEx(@GUI_DragFile, "*.*", -1)
     
    			For $i = 1 To $aFiles[0]
    				;Если это не файл .cue то продолжаем цикл далее
    				If StringRight($aFiles[$i], 4) <> ".cue" Then ContinueLoop
     
    				;Если в файле не найдено .wav то продолжаем цикл далее
    				If Not StringInStr(FileRead($aFiles[$i]), ".wav") Then ContinueLoop
    				
    				;Получаем путь к текущей папке
    				$sFolder = StringRegExpReplace($aFiles[$i], "\\[^\\]*$", "")
     
    				$sReplace = ""
     
    				;Проверяем существование файлов
    				Select
    					Case _FileGetFilesCount($sFolder, "*.ape") = 1
    						$sReplace = ".ape"
    					Case _FileGetFilesCount($sFolder, "*.flac") = 1
    						$sReplace = ".flac"
    					Case _FileGetFilesCount($sFolder, "*.wv") = 1
    						$sReplace = ".wv"
    					Case Else ;Ни один из нужных файлов не найден, продолжаем цикл далее
    						ContinueLoop
    				EndSelect
     
    				_ReplaceStringInFile($aFiles[$i], ".wav", $sReplace) 				
    			Next
				
				For $i = 1 To $aFiles[0]
    				;Если это не файл .cue то продолжаем цикл далее
    				If StringRight($aFiles[$i], 4) <> ".cue" Then ContinueLoop
     
    				;Если в файле не найдено .ape то продолжаем цикл далее
    				If Not StringInStr(FileRead($aFiles[$i]), ".ape") Then ContinueLoop
    				
    				;Получаем путь к текущей папке
    				$sFolder = StringRegExpReplace($aFiles[$i], "\\[^\\]*$", "")
     
    				$sReplace = ""
     
    				;Проверяем существование файлов
    				Select
    					Case _FileGetFilesCount($sFolder, "*.ape") = 1
    						$sReplace = ".ape"
    					Case _FileGetFilesCount($sFolder, "*.flac") = 1
    						$sReplace = ".flac"
    					Case _FileGetFilesCount($sFolder, "*.wv") = 1
    						$sReplace = ".wv"
    					Case Else ;Ни один из нужных файлов не найден, продолжаем цикл далее
    						ContinueLoop
    				EndSelect
     
    				_ReplaceStringInFile($aFiles[$i], ".ape", $sReplace) 				
    			Next
				
				For $i = 1 To $aFiles[0]
    				;Если это не файл .cue то продолжаем цикл далее
    				If StringRight($aFiles[$i], 4) <> ".cue" Then ContinueLoop
     
    				;Если в файле не найдено .wv то продолжаем цикл далее
    				If Not StringInStr(FileRead($aFiles[$i]), ".wv") Then ContinueLoop
    				
    				;Получаем путь к текущей папке
    				$sFolder = StringRegExpReplace($aFiles[$i], "\\[^\\]*$", "")
     
    				$sReplace = ""
     
    				;Проверяем существование файлов
    				Select
    					Case _FileGetFilesCount($sFolder, "*.ape") = 1
    						$sReplace = ".ape"
    					Case _FileGetFilesCount($sFolder, "*.flac") = 1
    						$sReplace = ".flac"
    					Case _FileGetFilesCount($sFolder, "*.wv") = 1
    						$sReplace = ".wv"
    					Case Else ;Ни один из нужных файлов не найден, продолжаем цикл далее
    						ContinueLoop
    				EndSelect
     
    				_ReplaceStringInFile($aFiles[$i], ".wv", $sReplace) 				
    			Next
    	EndSwitch
    WEnd
     
    Func _FileGetFilesCount($sPath, $sMask)
    	Local $aFiles = _FileListToArray($sPath, $sMask, 1)
    	Return UBound($aFiles)-1
    EndFunc
     
    Func _FileListToArrayEx($sPath, $sMask="*", $iMode=-1) ;$iMode > 0 только папки (маска игнорируется), иначе папки + файлы
    	If Not StringInStr(FileGetAttrib($sPath & "\"), "D") Then Return SetError(1, 0, 0)
     
    	Local $hSearch, $sFindNext, $sFilePath, $iPathIsFolder, $i = 0
    	Local $sRegExpFilter = StringReplace(StringReplace($sMask, ".", "\."), "*", ".*")
    	Local $iMax_Ret_Paths = 10000
    	Local $aPathesArr[$iMax_Ret_Paths+1] = [1, $sPath]
     
    	While $i < $aPathesArr[0]
    		$i += 1
     
    		$hSearch = FileFindFirstFile($aPathesArr[$i] & "\*")
    		If $hSearch = -1 Then ContinueLoop
     
    		While 1
    			$sFindNext = FileFindNextFile($hSearch)
    			If @error Then ExitLoop
     
    			$sFilePath = $aPathesArr[$i] & "\" & $sFindNext
    			$iPathIsFolder = StringInStr(FileGetAttrib($sFilePath & "\"), "D")
     
    			If $iMode <= 0 Or ($iMode > 0 And $iPathIsFolder) Then
    				If $iPathIsFolder Or (Not $iPathIsFolder And StringRegExp($sFindNext, "(?i)" & $sRegExpFilter)) Then
    					If $aPathesArr[0] >= $iMax_Ret_Paths Then
    						$iMax_Ret_Paths *= 2
    						ReDim $aPathesArr[$iMax_Ret_Paths+1]
    					EndIf
     
    					$aPathesArr[0] += 1
    					$aPathesArr[$aPathesArr[0]] = $sFilePath
    				EndIf
    			EndIf
    		WEnd
     
    		FileClose($hSearch)
    	Wend
     
    	ReDim $aPathesArr[$aPathesArr[0]+1]
    	Return $aPathesArr
    EndFunc
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Alexey
Вроде всё правильно.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Денис
посмотри код по внимательнее, там определение этой функции
Код:
Func _FileGetFilesCount($sPath, $sMask)
    Local $aFiles = _FileListToArray($sPath, $sMask, 1)
    Return UBound($aFiles)-1
EndFunc
 
Верх