Рекурсивная распаковка

Обсуждение вопросов автоматизации Total Commander с помощью сторонних программ и скриптовых технологий.

Модераторы: d-view, Моторокер, Avada, CaptainFlint, Nik

Аватара пользователя
D1P
Сообщения: 2987
Зарегистрирован: Пн дек 20, 2004 18:30
Откуда: Тбилиси
Контактная информация:

Рекурсивная распаковка

Сообщение D1P »

Дано: ветвистое дерево каталогов, вложенность может быть неограниченная. В каталогах файлы, запакованные обычным zip, несколько десятков тысяч всего.
Требуется распаковать все файлы с сохранением структуры каталогов.

Вариант вынести всё через Ctrl+B, распаковать, а потом каким-либо способом восстановить структуру не подходит, потому что такого способа нет.

Как решить задачу?
Аватара пользователя
Flasher
Сообщения: 14229
Зарегистрирован: Пт ноя 06, 2009 00:33
Откуда: Москва

Сообщение Flasher »

Пока неясно, куда распаковывать - в родительскую для каждого архива директорию или в новую одноимённую директорию, создаваемую внутри родительской?
Также неясно, что значит "с сохранением структуры"? Подразумевается, что при стандартном подходе содержимое всех архивов перекачует в общую папку, а не родительскую для каждого архива?

Мне кажется стоит подождать Tol!k, он скорректирует под сеи нужды этот батник.
Аватара пользователя
D1P
Сообщения: 2987
Зарегистрирован: Пн дек 20, 2004 18:30
Откуда: Тбилиси
Контактная информация:

Сообщение D1P »

>Пока неясно, куда распаковывать - в текущую для каждого архива директорию или в новую одноимённую директорию, создаваемую внутри текущей?

Проще всего объяснить так: на месте зипованых файлов должны оказаться раззипованные. Никаких новых директорий, никакого перемещения.
Аватара пользователя
Tol!k
Сообщения: 1727
Зарегистрирован: Вт апр 01, 2008 20:02
Откуда: Арзамас

Сообщение Tol!k »

параметры: "%L" "%%~dpf" -o
:!: важно выделять архивы (поиском или Ctrl+B), а не папку
Аватара пользователя
D1P
Сообщения: 2987
Зарегистрирован: Пн дек 20, 2004 18:30
Откуда: Тбилиси
Контактная информация:

Сообщение D1P »

Tol!k писал(а):параметры: "%L" "%%~dpf" -o
Спасибо. Это для твоего батника параметры?
Аватара пользователя
Flasher
Сообщения: 14229
Зарегистрирован: Пт ноя 06, 2009 00:33
Откуда: Москва

Сообщение Flasher »

Что-то вчера накидал (ин-ета не было - не мог выложить):

Код: Выделить всё

' Рекурсивная распаковка архивов внутри выделенных каталогов
' Параметры: %L <расширение архива>
'==========================================
Dim FSO, WSH
Set FSO = CreateObject("Scripting.FileSystemObject")
Set WSH = CreateObject("WScript.Shell")
Proga = WSH.ExpandEnvironmentStrings("%COMMANDER_PATH%\Utils\7-Zip\7z.exe")

With FSO.OpenTextFile(WScript.Arguments(0), 1)
  Do While Not .AtEndOfStream
    F = Trim(.ReadLine)
    If F <> "" Then
      If FSO.FolderExists(F) Then ForFolder FSO.GetFolder(F)
    End If
  Loop
  .Close
End With

WSH.Popup "Распаковка завершена!", 1.4, "Результат", 64
Set FSO = Nothing
Set WSH = Nothing
WScript.Quit

Sub ForFolder(Folder)
  Dim N
  For Each N In Folder.Files 
    ForFile N
  Next
  For Each N In Folder.SubFolders
    ForFolder N
  Next
End Sub

Sub ForFile(File)
  If LCase(FSO.GetExtensionName(File)) = LCase(WScript.Arguments(1)) Then WSH.Run """"  & Proga & """x """  & File & """ -o""" & File.ParentFolder & "\"" -y", 0, True
End Sub
См., чтобы путь к 7z.exe соответствовал.
Последний раз редактировалось Flasher Вт авг 02, 2011 12:32, всего редактировалось 2 раза.
Аватара пользователя
Tol!k
Сообщения: 1727
Зарегистрирован: Вт апр 01, 2008 20:02
Откуда: Арзамас

Сообщение Tol!k »

D1P писал(а):
Tol!k писал(а):параметры: "%L" "%%~dpf" -o
Спасибо. Это для твоего батника параметры?
Да, http://forum.wincmd.ru/viewpost.php?p=67240 Только без -o Извини, я похоже, уже спал:
-o — каждый архив в отдельную папку с именем архива
Аватара пользователя
D1P
Сообщения: 2987
Зарегистрирован: Пн дек 20, 2004 18:30
Откуда: Тбилиси
Контактная информация:

Сообщение D1P »

Tol!k
Спасибо, отличнейшим образом всё сработало.
Flasher
Тебе тоже спасибо.
Аватара пользователя
Flasher
Сообщения: 14229
Зарегистрирован: Пт ноя 06, 2009 00:33
Откуда: Москва

Сообщение Flasher »

D1P
Пож-та. Работа скрипта соответствует ТЗ, или что-то не так?
Аватара пользователя
Batya
Сообщения: 2236
Зарегистрирован: Ср дек 15, 2004 09:51
Откуда: Москва, Россия

Сообщение Batya »

Flasher
Пару советов:
1. При сравнении расширений "FSO.GetExtensionName(FilePath) = WScript.Arguments(1)" лучше приводить к одному регистру "UCase(FSO.GetExtensionName(FilePath)) = UCase(WScript.Arguments(1))" или использовать InStr "InStr(1, FSO.GetExtensionName(FilePath), WScript.Arguments(1), 1) > 0".
2. Думаю, что для поставленной задачи, т.к. арховов "несколько десятков тысяч", лучше использовать не параллельную распаковку, а последовательную. При вызове WSH.Run укажи третий параметр со значением True.
Нет, я не сплю. Я просто медленно моргаю.
Аватара пользователя
Flasher
Сообщения: 14229
Зарегистрирован: Пт ноя 06, 2009 00:33
Откуда: Москва

Сообщение Flasher »

Batya
1. ОК.
2. Изначально стояло True, просто кое-какие глюки c 7z были, процесс висеть оставался, но там причина, видимо, в другом была. Ещё вчера хотел вернуть, пост пачкать не хотелось. :roll: Хоть, конечно, для небольшого числа архивов параллельная распаковка проходит быстрее, не учесть большие списки нельзя, поэтому возвращаю True на место. К тому же сообщение будет появляться своевременно.
Аватара пользователя
D1P
Сообщения: 2987
Зарегистрирован: Пн дек 20, 2004 18:30
Откуда: Тбилиси
Контактная информация:

Сообщение D1P »

Flasher
До твоего скрипта руки не дошли, всё сделал батником.
Аватара пользователя
Flasher
Сообщения: 14229
Зарегистрирован: Пт ноя 06, 2009 00:33
Откуда: Москва

Сообщение Flasher »

D1P
А зря, сэкономил бы себе время.

2All
На всякий случай сообщаю тем, кому выгодней (например, мне) распаковывать каждый архив в создаваемую папку с базовым именем архива:
замените нижнюю процедуру на эту:

Код: Выделить всё

Sub ForFile(File)
  If LCase(FSO.GetExtensionName(File)) = LCase(WScript.Arguments(1)) Then
    On Error Resume Next
    NF = FSO.CreateFolder(File.ParentFolder & "\" & FSO.GetBaseName(File) & "\")
    WSH.Run """" & Proga & """ x """ & File & """ -o""" & NF & """ -y", 0, True
  End If
End Sub
Аватара пользователя
Volniy
Сообщения: 585
Зарегистрирован: Ср дек 15, 2004 00:17
Откуда: Местный

Сообщение Volniy »

Batya писал(а): 1. При сравнении расширений "FSO.GetExtensionName(FilePath) = WScript.Arguments(1)" лучше приводить к одному регистру "UCase(FSO.GetExtensionName(FilePath)) = UCase(WScript.Arguments(1))" или использовать InStr "InStr(1, FSO.GetExtensionName(FilePath), WScript.Arguments(1), 1) > 0"
...или использовать специально заточенную для сравнения строк функцию StrComp:

Код: Выделить всё

If StrComp(FSO.GetExtensionName(FilePath), WScript.Arguments(1) ,1) = 0 Then
Аватара пользователя
Flasher
Сообщения: 14229
Зарегистрирован: Пт ноя 06, 2009 00:33
Откуда: Москва

Сообщение Flasher »

Подумал, пусть тут тоже будет:

Код: Выделить всё

'•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
' Распаковка выделенных архивов и архивов в структуре
' выделенных каталогов в одноименные папки рядом с архивами
' Параметры: %L <расширения архивов через запятую>
' Пример: %L 7z,7zip,arc,bzip2,rar,zip

' Автор - Flasher ©
'•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••

Dim WSH, FSO
Set WSH = CreateObject("WScript.Shell")
Set FSO = CreateObject("Scripting.FileSystemObject")
Proga = WSH.ExpandEnvironmentStrings("%COMMANDER_PATH%\Utils\7-Zip\7z.exe")

With WScript.Arguments
  On Error Resume Next
  List = .Item(0)
  Filt = .Item(1)
  If Len(List) > 0 And .Count < 2 Then
    MsgBox  "Укажите оба параметра!",_
    vbExclamation, "  Рекурсивная упаковка"
    Wscript.Quit
  End If
End With

If Err.Number > 0 Then
  MsgBox  "Не выбраны элементы для распаковки!", vbExclamation,_
  "         Рекурсивная пофайловая распаковка"
End If

Set Dict = CreateObject("Scripting.Dictionary")
  Exts = "7z, 7zip, arj, bz2, bzip2, cab, chm, chw, cpio, cramfs, deb, dmg, doc, exe, fat, gz, gzip, hfs, hxs, iso, lha, lzma, mbr, msi, ntfs, ppt, rar, rpm, scap, squashfs, swm, tar, taz, tbz, tbz2, tgz, vhd, wim, xar, xls, xz, zip"
  For Each E in Split(Exts, ", ")
    Dict.Add Trim(E), ""
  Next
  
With FSO.OpenTextFile(List, 1)
  Do While Not .AtEndOfStream
    F = Trim(.ReadLine)
    If F <> "" Then
      If FSO.FolderExists(F) Then
        ForFolder FSO.GetFolder(F)  
      Else ForFile F
      End If
    End If
  Loop
  .Close
End With
Set Dict   = Nothing
WSH.Popup "Распаковка завершена!", 1.4 , "Результат", 64

Set WSH = Nothing
Set FSO  = Nothing
WScript.Quit

Sub ForFolder(Folder)
  Dim N
  For Each N In Folder.SubFolders
    ForFolder N
  Next
  For Each N In Folder.Files 
    ForFile N
  Next
End Sub

Sub ForFile(File)
  For Each Fi in Split(Filt,",")
    If StrComp(Fi,FSO.GetExtensionName(File),1) = 0 And Dict.Exists(LCase(Fi)) Then
      NF = FSO.CreateFolder(FSO.GetParentFolderName(File) & "\"  & FSO.GetBaseName(File) & "\" )
      WSH.Run """" & Proga & """ x """ & File & """ -o""" & NF & """ -y", 0, True
    End If
  Next
End Sub
Распаковываться будут архивы только с поддерживаемыми форматами (42 расширения).
Ответить