Что нового

[Данные, строки] Чтение файл-списка и формирование переменных.

gora

Знающий
Сообщения
315
Репутация
19
Имеется файл-список содержащий имена файлов и папок с полными путями.
Содержание его каждый раз разное. Каждый путь на отдельной строке. Число строк в файл-списке от 1 до неограниченно. Путь во всех строках одинаковый. Папки в списке могут иметь в конце слеш, но могут и не иметь его. Имена папок могут иметь точки в имени, а также точки могут присутствовать и в путях. Файлы могут иметь лишние точки в имени или вовсе не иметь расширения.
Требуется:
1 Найти в списке первые 4 файла и присвоить переменным $var1 ... $var4 значения равные полному пути\имени с расширением этих файлов. Если файлов будет меньше, то остальные переменные $var не определять.
2 Записать в переменную $allfile число найденных в п1 файлов (0...4)
3 Определить переменную $nameArchv следующим образом:
Если в списке только один пункт, то (
$nameArchv = полному пути\имени [в случае файла, без расширения] из этого пункта
) Иначе (
Если файлы/папки находятся в корне диска, то (
$nameArchv = имени_диска\ и слову "Archive"
) Иначе (
$nameArchv = полному_пути\имени_папки в которой находятся папки или файлы, т.е., имя последней папки будет использовано дважды.
)
)
Код, который это выполняет, я написал, но он мне не нравится. Прошу посмотреть его и, по возможности, подправить.
Спасибо.

Код:
;	формирование 4-х переменных с именами файлов, имени архива и числа найденых файлов (0...4)
$flagmany = 0
$allfile = 0
;$file = FileOpen($CmdLine[1], 0)
$file = FileOpen('filelist.tmp', 0)
While 1
	$line = FileReadLine($file)
	If @error = -1 Then ExitLoop
	$flagmany += 1
	If StringInStr(FileGetAttrib($line), 'D') Then
		If Not IsDeclared("nameArchv") Then
			$nameArchv = $line
			If StringRight($line, 1) = "\" Then $nameArchv = StringTrimRight($line, 1)
		EndIf
	Else
		$allfile += 1
		Assign("var" & $allfile, $line, 0)
		If Not IsDeclared("nameArchv") Then $nameArchv = StringRegExpReplace($line, '\.[^.]*$', '') ;Full path without File Extension
		If $allfile = 4 Then ExitLoop
	EndIf
Wend
FileClose($file)
$array = StringSplit($nameArchv, "\")
If $flagmany > 1 Then
	If $array[0] <= 2 Then
		$nameArchv = $array[1] & "\Archive"
	Else
		$nameArchv = StringTrimRight($nameArchv, StringLen($array[$array[0]])) & $array[$array[0]-1]
	EndIf
EndIf
;	================================================================================================
;	===== Тестовое окно ======
$preskey = MsgBox(1+256, "test", _
"$nameArchv = " & $nameArchv & @CRLF & _
"$allfile = " & $allfile & @CRLF & _
"$var1 = " & Eval("var1") & @CRLF & _
"$var2 = " & Eval("var2") & @CRLF & _
"$var3 = " & Eval("var3") & @CRLF & _
"$var4 = " & Eval("var4") & @CRLF & _
@CRLF)
If $preskey = 2 Then Exit
;	==========================


Пример файл-списка:
Код:
e:\DISTRIBUT\7-Zip\0_Button_Test\test\_Button.7z
e:\DISTRIBUT\7-Zip\0_Button_Test\test\test_ch\
e:\DISTRIBUT\7-Zip\0_Button_Test\test\1
e:\DISTRIBUT\7-Zip\0_Button_Test\test\_Button.7z.001
e:\DISTRIBUT\7-Zip\0_Button_Test\test\deflate.7z
e:\DISTRIBUT\7-Zip\0_Button_Test\test\1.exe
e:\DISTRIBUT\7-Zip\0_Button_Test\test\all.exe
e:\DISTRIBUT\7-Zip\0_Button_Test\test\ppmd.exe
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gora
ИМХО, эти данные лучше сохранить в массиве. Если я правильно понял Ваши условия, то:
Код:
#include <Array.au3>

Global $sFile = @ScriptDir & '\filelist.tmp', $iAllFiles = 0
Dim $aResult[$iAllFiles + 1][2]

If Not FileExists($sFile) Then
	MsgBox(16, 'Error', 'Не найден файл ' & $sFile)
	Exit
EndIf
$hFile = FileOpen($sFile, 0)
If $hFile = -1 Then
	MsgBox(16, 'Error', 'Не смог открыть файл ' & $sFile)
	Exit
EndIf
$sText = FileRead($hFile)
If Not $sText Then
	MsgBox(16, 'Error', 'Не смог прочитать файл ' & $sFile)
	FileClose($hFile)
	Exit
EndIf
FileClose($hFile)

$aTemp = StringSplit(StringStripCR($sText), @LF)
For $i = 1 To $aTemp[0]
	If FileExists($aTemp[$i]) Then
		$iAllFiles += 1
		If $iAllFiles > 4 Then
			$iAllFiles = 4
			ExitLoop
		EndIf
		ReDim $aResult[$iAllFiles + 1][2]
		$aResult[$iAllFiles][0] = $aTemp[$i]
		If StringInStr(FileGetAttrib($aTemp[$i]), 'D') Then
			If StringRight($aTemp[$i], 1) == '\' Then
				$aResult[$iAllFiles][1] = StringTrimRight($aTemp[$i], 1)
			Else
				$aResult[$iAllFiles][1] = $aTemp[$i]
			EndIf
		Else
			$aSplit = StringSplit($aTemp[$i], '\')
			If $aSplit[0] <= 2 Then
				$aResult[$iAllFiles][1] = $aSplit[1] & '\Archive'
			Else
				$aResult[$iAllFiles][1] = StringRegExpReplace($aTemp[$i], '\.[^.]*$', '') & '\' & _
						StringRegExpReplace($aTemp[$i], '.*\\|\.[^.]*$', '')
			EndIf
		EndIf

	EndIf
Next
If $iAllFiles Then
	$aResult[0][0] = $iAllFiles
	_ArrayDisplay($aResult)
Else
	MsgBox(16, 'Error', 'Ничего не найдено.')
EndIf
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
madmasles [?]
эти данные лучше сохранить в массиве. Если я правильно понял Ваши условия
Мне нужны на выходе только 6 переменных (в худшем случае 2, если в списке нет файлов), остальное мне не нужно. В чем здесь прелесть массива я не понял. Проверки на наличие и читабельность файла у меня уже есть и сделаны в скрипте ранее.
В Вашем варианте нет различий между файлами и папками в списке, а мне нужны только первые 4 файла, но не папки.
Переменная $nameArchv должна быть только одна и должна соответствовать первому пункту в списке, переопределять ее повторно не нужно.
Хотя может я и не прав, но что дальше делать с этим массивом я не понял.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gora
А так, если я правильно понял то, что нужно:
Код:
#include <Array.au3>

Global $sFile = @ScriptDir & '\filelist.tmp', $iAllFiles = 0, $sNameArchv, $sMessage
Dim $aResult[$iAllFiles + 1]

$hFile = FileOpen($sFile, 0)
If $hFile = -1 Then
	MsgBox(16, 'Error', 'Не смог открыть файл ' & $sFile)
	Exit
EndIf
$sText = FileRead($hFile)
FileClose($hFile)

$aTemp = StringSplit(StringStripCR($sText), @LF)
For $i = 1 To $aTemp[0]
	If FileExists($aTemp[$i]) Then
		If StringInStr(FileGetAttrib($aTemp[$i]), 'D') Then
			If $i = 1 Then
				If StringRight($aTemp[$i], 1) == '\' Then
					$sNameArchv = StringTrimRight($aTemp[$i], 1)
				Else
					$sNameArchv = $aTemp[$i]
				EndIf
			EndIf
		Else
			$iAllFiles += 1
			If $iAllFiles > 4 Then
				$iAllFiles = 4
				ExitLoop
			EndIf
			ReDim $aResult[$iAllFiles + 1]
			$aResult[$iAllFiles] = $aTemp[$i]
			If $i = 1 Then
				If $aTemp[0] > 1 Then
					$aSplit = StringSplit($aTemp[$i], '\')
					If $aSplit[0] <= 2 Then
						$sNameArchv = $aSplit[1] & '\Archive'
					Else
						$sNameArchv = StringRegExpReplace($aTemp[$i], '\\[^\\]*$', '') & '\' & _
								StringRegExpReplace(StringRegExpReplace($aTemp[$i], '\\[^\\]*$', ''), '.*\\|\.[^.]*$', '')
					EndIf
				Else
					$sNameArchv = StringRegExpReplace($aTemp[$i], '\.[^.]*$', '')
				EndIf
			EndIf
		EndIf

	EndIf
Next
If $iAllFiles Then
	$aResult[0] = $iAllFiles
	_ArrayDisplay($aResult, $sNameArchv)
	;или
	For $i = 1 To $aResult[0]
		$sMessage &= $i & '.' & @TAB & $aResult[$i] & @LF
	Next
	$sMessage &= 'iAllFiles:' & @TAB & $aResult[0] & @LF & @LF
	$sMessage &= 'sNameArchv:' & @TAB & $sNameArchv
	MsgBox(64, 'Info', $sMessage)
Else
	If $sNameArchv Then
		MsgBox(64, 'Info', 'Файлов не найдено.' & @LF & 'sNameArchv:' & @TAB & $sNameArchv)
	Else
		MsgBox(16, 'Error', 'Ничего не найдено.')
	EndIf
EndIf
В массиве $aResult, начиная с индекса 1, хранятся найденные файлы, в $aResult[0] - количество найденных файлов.
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
madmasles
C именем архива не получилось. :(
Ваш вариант:
11.png


Мой:
12.png
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gora [?]
Переменная $nameArchv должна быть только одна и должна соответствовать первому пункту в списке, переопределять ее повторно не нужно.
Я так и не понял, какое значение эта переменная должна иметь. :wacko:
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
madmasles, может я конечно сложно объяснил, она определяется по такому алгоритму.
gora [?]
3 Определить переменную $nameArchv следующим образом:
Если в списке только один пункт, то (
$nameArchv = полному пути\имени [в случае файла, без расширения] из этого пункта
) Иначе (
Если файлы/папки находятся в корне диска, то (
$nameArchv = имени_диска\ и слову "Archive"
) Иначе (
$nameArchv = полному_пути\имени_папки в которой находятся папки или файлы, т.е., имя последней папки будет использовано дважды.
)
)
Просто ее нужно определять только один раз по первой строке в списке, а не переопределять ее при обработке каждой строки.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gora
Давайте уточним. Если есть файлы, то $sNameArchv определяется по первому найденному файлу, если файлов нет, но есть папки, то по первой найденной папке, если нет ни того, ни другого, то она ="".
Я правильно понял?
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
madmasles
Давайте.
madmasles [?]
если нет ни того, ни другого, то она ="".
Такого быть не может по условиям задачи

$sNameArchv определяется по первому пункту списка, не зависимо от того, что это файл или папка. Только в случае файла у него будет отброшено расширение. Это если пункт один.
Пример:
Пункт: e:\DISTRIBUT\7-Zip\0_Button_Test\test\_Button.7z
Если это файл, то:
$sNameArchv = e:\DISTRIBUT\7-Zip\0_Button_Test\test\_Button
Если это папка, то:
$sNameArchv = e:\DISTRIBUT\7-Zip\0_Button_Test\test\_Button.7z
-----------------------------------------------------------------
Если пункт не один и не в корне диска, то должно быть так:
Первый пункт: e:\DISTRIBUT\7-Zip\0_Button_Test\test\_Button.7z
$sNameArchv = e:\DISTRIBUT\7-Zip\0_Button_Test\test\test
Т.е. именем становится имя родительской папки
-----------------------------------------------------------------
Если пункт не один и в корне диска, то должно быть так:
Первый пункт: e:\_Button.7z
$sNameArchv = e:\Archive
где Archive - фиксированное имя
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gora
Я поправил код. Вроде, правильно. :smile:

Еще поправил.
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
madmasles
C именем архива опять неувязка. :(
Файл-список:
Код:
F:\Test_7zip\_test1\333\
F:\Test_7zip\_test1\test\
F:\Test_7zip\_test1\deflate.7z
F:\Test_7zip\_test1\all.exe
F:\Test_7zip\_test1\256_128_48_32_24_16.ico
F:\Test_7zip\_test1\3.res
Две первые - папки, остальные файлы.
в
$sNameArchv=F:\Test_7zip\_test1\333
а должно быть
$sNameArchv=F:\Test_7zip\_test1\_test1

Ваш код получается сложнее моего... :( Видимо не судьба его уменьшить, наплюйте.
Спасибо Вам за потраченное на меня время.

PS
Вынес определение имени архива из цикла и все стало проще:
Код:
$flagmany = 0
$allfile = 0
;$file = FileOpen($CmdLine[1], 0)
$file = FileOpen('filelist.tmp', 0)
While 1
	$line = FileReadLine($file)
	If @error = -1 Then ExitLoop
	$flagmany += 1
	If Not IsDeclared("nameArchv") Then $nameArchv = $line
	If Not StringInStr(FileGetAttrib($line), 'D') Then
		$allfile += 1
		Assign("var" & $allfile, $line, 0)
		If $allfile = 4 Then ExitLoop
	EndIf
Wend
FileClose($file)
If StringRight($nameArchv, 1) = "\" Then $nameArchv = StringTrimRight($nameArchv, 1)
$array = StringSplit($nameArchv, "\")
If $flagmany > 1 Then
	If $array[0] <= 2 Then
		$nameArchv = $array[1] & "\Archive"
	Else
		$nameArchv = StringTrimRight($nameArchv, StringLen($array[$array[0]])) & $array[$array[0]-1]
	EndIf
Else
	If Not StringInStr(FileGetAttrib($nameArchv), 'D') Then $nameArchv = StringRegExpReplace($nameArchv, '\.[^.]*$', '')
EndIf
 
Верх