Страница 1 из 36

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

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

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

Как решить задачу?

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

Мне кажется стоит подождать Tol!k, он скорректирует под сеи нужды этот батник.

Добавлено: Вс июл 31, 2011 20:08
D1P
>Пока неясно, куда распаковывать - в текущую для каждого архива директорию или в новую одноимённую директорию, создаваемую внутри текущей?

Проще всего объяснить так: на месте зипованых файлов должны оказаться раззипованные. Никаких новых директорий, никакого перемещения.

Добавлено: Пн авг 01, 2011 00:55
Tol!k
параметры: "%L" "%%~dpf" -o
:!: важно выделять архивы (поиском или Ctrl+B), а не папку

Добавлено: Пн авг 01, 2011 08:18
D1P
Tol!k писал(а):параметры: "%L" "%%~dpf" -o
Спасибо. Это для твоего батника параметры?

Добавлено: Пн авг 01, 2011 17:44
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 соответствовал.

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

Добавлено: Пн авг 01, 2011 21:15
D1P
Tol!k
Спасибо, отличнейшим образом всё сработало.
Flasher
Тебе тоже спасибо.

Добавлено: Пн авг 01, 2011 21:17
Flasher
D1P
Пож-та. Работа скрипта соответствует ТЗ, или что-то не так?

Добавлено: Вт авг 02, 2011 10:01
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.

Добавлено: Вт авг 02, 2011 12:23
Flasher
Batya
1. ОК.
2. Изначально стояло True, просто кое-какие глюки c 7z были, процесс висеть оставался, но там причина, видимо, в другом была. Ещё вчера хотел вернуть, пост пачкать не хотелось. :roll: Хоть, конечно, для небольшого числа архивов параллельная распаковка проходит быстрее, не учесть большие списки нельзя, поэтому возвращаю True на место. К тому же сообщение будет появляться своевременно.

Добавлено: Вт авг 02, 2011 19:11
D1P
Flasher
До твоего скрипта руки не дошли, всё сделал батником.

Добавлено: Вт авг 02, 2011 19:34
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

Добавлено: Чт авг 04, 2011 04:05
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

Добавлено: Сб авг 13, 2011 23:56
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 расширения).