Что нового

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

Alexey

Чайник
Сообщения
171
Репутация
0
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!
Команда форума
Администратор
Сообщения
8 159
Репутация
2 329
Вот так примерно:

Код:
#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

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

Yashied

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

Alexey

Чайник
Сообщения
171
Репутация
0
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

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

CreatoR

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

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

Alexey

Чайник
Сообщения
171
Репутация
0
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!
Команда форума
Администратор
Сообщения
8 159
Репутация
2 329
Alexey
Вроде всё правильно.
 

kaster

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