2017-04-22 88 views
1

我有很多RAR或ZIP壓縮文件。某些檔案包含一個包含此文件夾中所有文件的文件夾。其他一些檔案在根級別具有所有文件。如何在RAR/ZIP提取中創建子文件夾,如果歸檔文件沒有?

案例01

Archive01.rar 
    MyFolder 
     file01.txt 
     file02.txt 
     file03.txt 
     etc. 

案例02

Archive02.rar 
    -file01.txt 
    -file02.txt 
    -file031.txt 
    etc. 

我知道如何提取所有檔案到子文件夾。

但是,如何僅在檔案中不存在時創建子文件夾?

我的意思是在處理數千個檔案的批處理過程中,如果歸檔文件屬於案例01,那麼在抽取時不應創建額外的文件夾。但是,如果歸檔文件屬於情況02,則應將提取操作寫入歸檔文件名稱的子文件夾中。

案01結果

MyFolder <- Folder 
    file01.txt 
    file02.txt 
    file03.txt 
    etc. 

案02結果

Archive02 <-Folder base on the archive name 
    -file01.txt 
    -file02.txt 
    -file031.txt 
    etc. 
+0

你是什麼意思「的意思,但不是如何創建它,只有當不存在?「 –

+0

如果檔案是「案例01」,我不創建文件夾,如果「案例02」我創建了一個文件夾來提取所有文件。 –

回答

2

的控制檯版本Rar.exe有命令l列表歸檔文件根據文本文件Rar.txt的內容在的程序文件文件夾中WinRAR是控制檯版本的手冊。使用命令l(或L)運行Rar.exe的列表輸出可以在批處理文件中進行處理,以確定RAR存檔文件是否在頂層僅包含單個目錄,而不包含其他任何內容。但Rar.exe支持像免費UnRAR.exe只是RAR檔案。

要支持ZIP存檔,則需要使用GUI版本WinRAR.exe,該版本支持提取RAR和ZIP存檔以及其他存檔類型。

該手冊爲WinRAR.exe幫助WinRAR的它可以在點擊菜單幫助上的菜單項幫助主題上運行WinRAR的打開。在幫助選項卡內容有列表項目命令行模式與參考幫助頁面中的所有必要信息從命令行運行WinRAR.exe

它可以在看好命令列表WinRAR.exe不支持命令l輸出檔案文件的內容,因爲是一個圖形用戶界面應用程序控制臺窗口中看到。

因此,從命令行或批處理文件中確定歸檔文件是否僅包含使用WinRAR.exe時的單個目錄的最高級別是不可能的。

但是,這並不重要,因爲首先解析文件和目錄名稱的歸檔文件,然後使用相應的命令在命令行上或在命令行上指定額外的解壓縮文件夾的情況下解壓縮歸檔文件效率不高。

這是更有效的先提取所有的* .rar程序(後來也全部* .zip文件)只使用一個WinRAR的電話與開關-ad文件到每個存檔文件解壓縮到一個子目錄與歸檔文件的名稱第二,刪除每個提取目錄不是必需的,因爲相應的存檔文件只包含頂級目錄中的單個目錄。

這種聰明的做法是在批處理文件中使用以下其中包含以下附加功能,使之成爲希望很多WinRAR的用戶有用:

  1. 的工作目錄可以被指定爲第一個參數上調用批文件甚至可以是UNC路徑。

  2. 批處理文件找出自動哪裏WinRAR.exe安裝工作也不被安裝在默認的Program Files目錄中的用例與32位或64位的WinRAR(如在所有的我的電腦)。

注:註釋的批處理文件貼在下面,如果在當前或指定目錄中的現有檔案文件已被提取之前不檢查。因此,建議不要在一個目錄中多次運行該批處理文件,而該目錄的存檔文件一旦被處理時不會從該目錄中刪除。

@echo off 
rem Change working directory if batch file was started with an argument. 
if not "%~1" == "" (
    pushd "%~1" 2>nul 
    if errorlevel 1 (
     echo Specified directory "%~1" does not exist. 
     echo/ 
     pause 
     goto :EOF 
    ) 
) 

setlocal EnableExtensions DisableDelayedExpansion 

rem Does WinRAR exist in default program files folder? 
set "WinRAR=%ProgramFiles%\WinRAR\WinRAR.exe" 
if exist "%WinRAR%" goto StartExtraction 

rem Does WinRAR exist in default program files folder for x86 applications? 
set "WinRAR=%ProgramFiles(x86%\WinRAR\WinRAR.exe" 
if exist "%WinRAR%" goto StartExtraction 

rem Try to determine installation location of WinRAR.exe from registry. 
set "TypeToken=2" 
goto GetPathFromRegistry 

rem On Windows Vista and later REG.EXE outputs without version info: 

rem HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe 
rem (Default) REG_SZ Full path to WinRAR\WinRAR.exe 

rem There are only spaces used to separate value name, value type and value string. 

rem But REG.EXE version 3.0 outputs on Windows XP with version info: 

rem ! REG.EXE VERSION 3.0 
rem 
rem HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe 
rem  <NO NAME> REG_SZ Full path to WinRAR\WinRAR.exe 

rem NOTE: There are 4 indent spaces and 2 separating tabs in REG 3.0 output line. 

rem So either token 2 or token 3 contains value type REG_SZ 
rem used to identify the line with the wanted information. 

:GetPathFromRegistry 
for /F "skip=1 tokens=%TypeToken%*" %%A in ('%SystemRoot%\System32\reg.exe QUERY "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe" /ve 2^>nul') do (
    if "%%A" == "REG_SZ" (
     if exist "%%~fB" (
      set "WinRAR=%%~fB" 
      goto StartExtraction 
     ) 
    ) else if "%%A" == "NAME>" (
     set "TypeToken=3" 
     goto GetPathFromRegistry 
    ) 
) 

endlocal 
if not "%~1" == "" popd 
echo Could not determine directory containing WinRAR.exe. 
echo/ 
echo Please configure it manually in file: %~f0 
echo/ 
pause 
goto :EOF 


rem WinRAR supports multiple archive types on extraction. 
rem Specify here the archive file extensions for extraction. 

:StartExtraction 
for %%I in (rar zip) do call :ExtractArchives %%I 

rem Restore previous command environment, restore previous current directory 
rem and exit this batch file without fall through to the subroutines below. 
endlocal 
if not "%~1" == "" popd 
goto :EOF 


rem The subroutine ExtractArchives processes all archive files in current 
rem directory with the file extension passed to subroutine as first argument. 

rem WinRAR is called once to extract all files with specified file extension 
rem for extraction into a subdirectory with name of the archive file. 

rem Then one more subroutine is called for each archive file to determine 
rem if it is safe to move the extracted archive file contents up one level. 

:ExtractArchives 
if not exist "*.%~1" goto :EOF 
"%WinRAR%" x -ad -cfg- -ibck -y -- "*.%~1" 
for %%A in ("*.%~1") do call :MoveUpExtracted "%%~nA" 
goto :EOF 

rem The subroutine MoveUpExtracted first checks if for the archive file 
rem passed to the subroutine as first argument a subdirectory exists at 
rem all, i.e. the extraction before was successful for that archive. 

rem Next it counts the subdirectories in the archive extraction directory. 
rem Nothing is moved up if there is more than 1 subdirectory in archive 
rem extraction directory. 

rem Also nothing is moved up if archive extraction directory contains 
rem 1 or more files. 

rem After verification of archive extraction directory really containing 
rem only a single subdirectory and nothing else, the name of the archive 
rem extraction directory is compared case-insensitive with the name of 
rem the single subdirectory in archive extraction directory. On equal 
rem directory names the archive extraction directory is renamed by 
rem appending _tmp to make it possible to move the subdirectory with same 
rem name up one level in directory hierarchy. There is hopefully by chance 
rem never a directory present in current directory with name of an archive 
rem file and _tmp appended. 

rem Next it is checked if in current directory there is not already existing 
rem a directory with name of the subdirectory from extracted archive in which 
rem case it is also not possible to move the directory up one level. In this 
rem special use case the archive extraction directory is kept containing just 
rem a single subdirectory with restoring original directory name. 

rem Then the single subdirectory in archive extraction directory is moved up 
rem one level which is very fast as just the file allocation table is updated 
rem and no data is really moved. 

rem The directory movement could fail if the extracted directory has hidden 
rem attribute set. In this case temporarily remove the hidden attribute, 
rem move the directory up one level in directory hierarchy and set the 
rem hidden attribute again on the directory. 

rem On a succesful moving up of the extracted directory the (renamed) 
rem extraction directory being now empty is deleted as not further needed. 


:MoveUpExtracted 
if not exist "%~1\" (
    echo Error: No folder for archive %~1 
    goto :EOF 
) 

echo Processing archive folder "%~1" 
set FolderCount=0 
set "FolderName=" 
for /F "delims=" %%D in ('dir "%~1\*" /AD /B 2^>nul') do (
    if defined FolderName goto :EOF 
    set /A FolderCount+=1 
    set "FolderName=%%D" 
) 
if not %FolderCount% == 1 goto :EOF 

for /F "delims=" %%F in ('dir "%~1\*" /A-D /B 2^>nul') do goto :EOF 

set "ParentRenamed=0" 
set "ParentFolder=%~1" 
if /I "%~1" == "%FolderName%" (
    ren "%~1" "%~1_tmp" 2>nul 
    if errorlevel 1 (
     echo Failed to rename "%~1" to "%~1_tmp". 
     goto :EOF 
    ) 
    set "ParentFolder=%~1_tmp" 
    set "ParentRenamed=1" 
) 

if exist "%FolderName%" (
    if %ParentRenamed% == 1 ren "%~1_tmp" "%~1" 
    echo Error: Folder exists "%FolderName%" 
    goto :EOF 
) 

move "%ParentFolder%\%FolderName%" "%FolderName%" >nul 2>nul 
if not errorlevel 1 (
    rd "%ParentFolder%" 
    goto :EOF 
) 

%SystemRoot%\System32\attrib.exe -h "%ParentFolder%\%FolderName%" >nul 
move "%ParentFolder%\%FolderName%" "%FolderName%" >nul 
if errorlevel 1 (
    if %ParentRenamed% == 1 (
     ren "%ParentFolder%" "%~1" 
     goto :EOF 
    ) 
) 

%SystemRoot%\System32\attrib.exe +h "%FolderName%" 
rd "%ParentFolder%" 
goto :EOF 

我使用的是32位Windows自Windows 95,但我跑我自己從來沒有進入MAX_PATH限制,即絕對的文件/文件夾名稱長於259個字符。

因此,當歸檔文件名非常長時(例如,文件名+文件擴展名只有256個字符),重寫批處理文件以使其工作也非常有趣並且非常耗時。

在我下面的批處理文件的發展找到了以下內容:

  1. DIRFORRDREN支持短8.3路徑名稱和一些命令文件/文件夾名稱,而其他命令如ATTRIBMOVE僅在路徑中支持它們,但不支持文件/文件夾名稱(至少在Windows XP上)。
    所以無法使用其簡短的8.3名稱來移動文件夾或更改其屬性。

  2. 當包含完整路徑的文件夾名稱長於259個字符時,所有命令都無法使用相對文件夾路徑使用相對文件夾名稱。這意味着Windows命令解釋器在執行任何命令之前首先使用完整路徑確定文件夾名稱。所以當前目錄應該有一個很短的路徑來處理具有很長名稱或包含名稱很長的目錄的檔案。

  3. 我無法弄清楚如何獲得一個文件夾的短名稱或使用由for /?解釋的時候只是一個相對的文件夾路徑是由Windows命令解釋器解析%~fs1(批處理文件)由call /?%%~fsI解釋其路徑,即只是沒有路徑的文件夾的長名稱。

  4. 在運行命令DIR與選項/X獲取目錄的短名稱,第三列包含短名稱和第四列的長名稱。但是第三列中的短名稱可能會在很短的文件夾名稱中丟失。

    Volume in drive C is System 
    Volume Serial Number is 7582-4210 
    
    Directory of C:\Temp\Test 
    
    29.04.2017 22:39 <DIR>      . 
    29.04.2017 22:39 <DIR>      .. 
    29.04.2017 22:39 <DIR>   ARCHIV~1  archive_with_a_very_very_very_..._long_name_1 
    29.04.2017 22:39 <DIR>      Batch 
    29.04.2017 22:39 <DIR>      xyz 
    

    同一命令dir /AD /X在德國的Windows XP SP3的x86執行:的dir /AD /X英文版Windows 7 SP1 64位

輸出在NTFS分區上與德國執行在Windows區域和語言設置來設置

Datenträger in Laufwerk F: ist TEMP 
Volumeseriennummer: CAA5-41AA 

Verzeichnis von F:\Temp 

29.04.2017 22:39 <DIR>      . 
29.04.2017 22:39 <DIR>      .. 
29.04.2017 22:39 <DIR>   BATCH  Batch 
29.04.2017 22:39 <DIR>      xxx 
29.04.2017 22:39 <DIR>   ARCHIV~1  archive_with_a_very_very_very_..._long_name_1 

注:FAT32分區還與德國在Windows區域和語言設置來設置這個非常長的目錄名在我的名字中被截斷了...

爲什麼目錄Batch在Windows XP計算機上有簡稱BATCH但在Windows 7上沒有短名稱對我來說真的不能解釋。

下面是批處理腳本,只要當前目錄的路徑很短,就可以在歸檔中支持長歸檔名稱和長目錄名稱。

@echo off 
rem Change working directory if batch file was started with an argument. 
if not "%~1" == "" (
    pushd "%~1" 2>nul 
    if errorlevel 1 (
     echo Specified directory "%~1" does not exist. 
     echo/ 
     pause 
     goto :EOF 
    ) 
) 

setlocal EnableExtensions DisableDelayedExpansion 

rem Does WinRAR exist in default program files folder? 
set "WinRAR=%ProgramFiles%\WinRAR\WinRAR.exe" 
if exist "%WinRAR%" goto StartExtraction 

rem Does WinRAR exist in default program files folder for x86 applications? 
set "WinRAR=%ProgramFiles(x86%\WinRAR\WinRAR.exe" 
if exist "%WinRAR%" goto StartExtraction 

rem Try to determine installation location of WinRAR.exe from registry. 
set "TypeToken=2" 
goto GetPathFromRegistry 

rem On Windows Vista and later REG.EXE outputs without version info: 

rem HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe 
rem (Default) REG_SZ Full path to WinRAR\WinRAR.exe 

rem There are only spaces used to separate value name, value type and value string. 

rem But REG.EXE version 3.0 outputs on Windows XP with version info: 

rem ! REG.EXE VERSION 3.0 
rem 
rem HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe 
rem  <NO NAME> REG_SZ Full path to WinRAR\WinRAR.exe 

rem NOTE: There are 4 indent spaces and 2 separating tabs in REG 3.0 output line. 

rem So either token 2 or token 3 contains value type REG_SZ 
rem used to identify the line with the wanted information. 

:GetPathFromRegistry 
for /F "skip=1 tokens=%TypeToken%*" %%A in ('%SystemRoot%\System32\reg.exe QUERY "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe" /ve 2^>nul') do (
    if "%%A" == "REG_SZ" (
     if exist "%%~fB" (
      set "WinRAR=%%~fB" 
      goto StartExtraction 
     ) 
    ) else if "%%A" == "NAME>" (
     set "TypeToken=3" 
     goto GetPathFromRegistry 
    ) 
) 

endlocal 
if not "%~1" == "" popd 
echo Could not determine directory containing WinRAR.exe. 
echo/ 
echo Please configure it manually in file: %~f0 
echo/ 
pause 
goto :EOF 


rem WinRAR supports multiple archive types on extraction. 
rem Specify here the archive file extensions for extraction. 

rem But first delete temporary folder from a previous breaked execution. 

:StartExtraction 
rd /Q /S # 2>nul 

for %%I in (rar zip) do call :ExtractArchives %%I 

rem Restore previous command environment, restore previous current directory 
rem and exit this batch file without fall through to the subroutines below. 
endlocal 
if not "%~1" == "" popd 
goto :EOF 


rem The subroutine ExtractArchives processes all archive files in current 
rem directory with the file extension passed to subroutine as first argument. 

rem WinRAR is called once to extract all files with specified file extension 
rem for extraction into a subdirectory with name of the archive file. 

rem Then one more subroutine is called for each archive file to determine 
rem if it is safe to move the extracted archive file contents up one level. 

:ExtractArchives 
if not exist "*.%~1" goto :EOF 
"%WinRAR%" x -ad -cfg- -ibck -y -- "*.%~1" 
for %%A in ("*.%~1") do call :MoveUpExtracted "%%~nA" %1 
goto :EOF 

rem The subroutine MoveUpExtracted first checks if for the archive file 
rem passed to the subroutine as first argument a subdirectory exists at 
rem all, i.e. the extraction before was successful for that archive, and 
rem determines short 8.3 name of this directory. 

rem Next it counts the subdirectories in the archive extraction directory 
rem using short directory name. Nothing is moved up if there is more than 
rem 1 subdirectory in archive extraction directory. 

rem Also nothing is moved up if archive extraction directory contains 
rem 1 or more files. 

rem After verification of archive extraction directory really containing 
rem only a single subdirectory and nothing else, the current archive folder 
rem is renamed to # (single character folder name) using short folder name. 

rem This folder rename should work in general. The current archive folder 
rem is kept in case of this folder rename fails unexpected because it is 
rem not yet known if the current directory does not already contain the 
rem single directory extracted from current archive or rename failed 
rem because of a permission or a directory sharing access restriction. 

rem Next it is checked if in current directory there is not already existing 
rem a directory with name of the subdirectory from extracted archive in which 
rem case it is also not possible to move the directory up one level. In this 
rem special use case the archive extraction directory is kept containing just 
rem a single subdirectory with restoring original directory name. In case of 
rem restoring archive directory fails unexpected, the directory with name # 
rem is deleted and the archive is extracted once again into a directory with 
rem name of archive file. 

rem It is clear on this point that the single directory in archive extraction 
rem directory can be moved up to current directory from directory wit having 
rem now the temporary name #. 

rem Moving a directory with command MOVE is not possible if hidden attribute 
rem is set on directory. For that reason it is checked next if the directory 
rem to move up has hidden attribute set using its short directory name. 

rem In case of directory has hidden attribute is indeed set, it is removed 
rem which is also verified. The verification can't be done with errorlevel 
rem evaluation as external command ATTRIB does not set errorlevel on failed 
rem attribute change. So the attribute check is done once again after the 
rem hidden attribute is removed with ATTRIB. 

rem ATTRIB also fails to change the attribute if absolute folder path is 
rem longer than 259 characters. In this case the current extraction folder 
rem with temporary name # is deleted completely and the current archive is 
rem extracted once again to current directory without creation of an 
rem additional directory with name of archive file. 

rem Then the single subdirectory in archive extraction directory having 
rem now name # is also renamed to # using short directory name to avoid 
rem a problem on next command MOVE with an absolute folder path longer 
rem than 259 characters as much as possible. 

rem The directory extracted from archive with name # in directory # is 
rem moved up to current directory with suppressing all errors which could 
rem occur for example if path of current directory plus name of directory 
rem as extracted from archive file is too long. 

rem The directory # in current directory with its subdirectory # is deleted 
rem on a moving error and the current archive file is extracted once again 
rem into current directory without creation of an additional directory with 
rem name of archive file. 

rem But on successful movement of the folder with correct name to current 
rem directory the hidden attribute is set on folder if the extracted folder 
rem has it also set before moving the folder and the finally empty folder # 
rem is deleted before exiting subroutine. 


:MoveUpExtracted 
set "FolderToCheck=%~f1" 
set "FolderToCheck=%FolderToCheck:~0,258%" 
for /F "skip=5 tokens=4*" %%X in ('dir "%FolderToCheck%*" /AD /X 2^>nul') do (
    if "%%Y" == "%~1" set "ArchiveFolder=%%X" & goto Subfolders 
    if "%%Y" == "" if /I "%%X" == "%~1" set "ArchiveFolder=%%X" & goto Subfolders 
) 
echo Error: No folder for archive %~1 
goto :EOF 

:Subfolders 
@echo off 
echo Processing archive folder "%~1" 
set FolderCount=0 
set "FolderName=" 
for /F "delims=" %%D in ('dir "%ArchiveFolder%\*" /AD /B 2^>nul') do (
    if defined FolderName goto :EOF 
    set /A FolderCount+=1 
    set "FolderName=%%D" 
) 
if not %FolderCount% == 1 goto :EOF 

for /F "delims=" %%F in ('dir "%ArchiveFolder%\*" /A-D /B 2^>nul') do goto :EOF 

ren "%ArchiveFolder%" # 2>nul 
if errorlevel 1 (
    echo Error: Failed to rename "%~1" 
    goto :EOF 
) 

set "FolderToCheck=%~dp1%FolderName%" 
set "FolderToCheck=%FolderToCheck:~0,258%" 
for /F "skip=5 tokens=4*" %%X in ('dir "%FolderToCheck%*" /AD /X 2^>nul') do (
    if "%%Y" == "%FolderName%" goto FolderExist 
    if "%%Y" == "" if /I "%%X" == "%FolderName%" goto FolderExist 
) 

set "HiddenFolder=0" 
set "FolderToCheck=%~dp1#\%FolderName%" 
set "FolderToCheck=%FolderToCheck:~0,258%" 
for /F "skip=5 tokens=4*" %%X in ('dir "%FolderToCheck%*" /AD /X 2^>nul') do (
    if "%%Y" == "%FolderName%" set "FolderToMove=%%X" & goto CheckHidden 
    if "%%Y" == "" if /I "%%X" == "%FolderName%" set "FolderToMove=%%X" & goto CheckHidden 
) 

:CheckHidden 
for %%X in ("#\%FolderToMove%") do (
    for /F "tokens=2 delims=h" %%H in ("%%~aX") do (
     if %HiddenFolder% == 1 goto ArchiveExtract 
     set "HiddenFolder=1" 
     %SystemRoot%\System32\attrib.exe -h "#\%FolderName%" 
     goto CheckHidden 
    ) 
) 

ren "#\%FolderToMove%" # 2>nul 
move #\# "%FolderName%" >nul 2>nul 
if errorlevel 1 goto ArchiveExtract 

if %HiddenFolder% == 1 %SystemRoot%\System32\attrib.exe +h "%FolderName%" 
rd # 
goto :EOF 

:ArchiveExtract 
rd /Q /S # 
"%WinRAR%" x -cfg- -ibck -y -- "%~1.%~2" 
goto :EOF 

:FolderExist 
echo Error: Folder exists "%FolderName%" 
ren # "%~1" 2>nul 
if not errorlevel 1 goto :EOF 
rd /Q /S # 
"%WinRAR%" x -ad -cfg- -ibck -y -- "%~1.%~2" 
goto :EOF 

這將是肯定更好地編寫C或C++以上批處理腳本控制檯應用程序或C#是長路徑意識到更換子程序MoveUpExtracted

在Windows 10版本1607(週年更新)或更高版本的Windows版本的MAX_PATH限260個字符(259個字符加上終止空字節),可以通過組策略或通過添加註冊表值被禁用,請參閱

對於理解使用的命令以及它們如何工作,打開命令提示符窗口中,執行的有以下命令,並仔細閱讀爲每個命令顯示的所有幫助頁面。

  • attrib /?
  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • move /?
  • pause /?
  • popd /?
  • pushd /?
  • rd /?
  • reg /?
  • reg query /?
  • rem /?
  • ren /?
  • set /?
  • setlocal /?

閱讀也是微軟的文章:

+0

非常感謝!它的工作原理與我夢想的一樣:*)你讓我的一天! –

-1

你必須檢查,如果數據是內部文件夾或根。

如果它的根點擊extract to /foldername(案例02)

否則只提取這裏(案例01)

enter image description here

+1

謝謝,但我不能用15000個檔案來做到這一點:*)我需要一個批處理解決方案! –

相關問題