Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Удаление одинаковых файлов по размеру (http://forum.oszone.net/showthread.php?t=211303)

Arsenik77 16-07-2011 10:41 1714450

Удаление одинаковых файлов по размеру
 
Добрый день, нужен батник который сравнивал и удалял одинаковые по размеру файлы в одной папке (и оставлял только один).
Сторонние программы не хочу использовать, нужно именно bat.

root221 16-07-2011 11:49 1714478

Код:

@Echo off
set Size=66
set Files=C:\help\*.*
rem Если размер должен быть равным или меньшим Size, то EQU заменить на LEQ
for %%L in (%Files%) do if /i %%~zL EQU %Size% del /f "%%L"


Iska 16-07-2011 12:41 1714509

Цитата:

Цитата Arsenik77
Сторонние программы не хочу использовать, нужно именно bat. »

Как насчёт скрипта VBScript?
Код:

Option Explicit

Dim objFSO
Dim strFolder
Dim objFile
Dim objDictionary
Dim elem


If WScript.Arguments.Count = 1 Then
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        strFolder = WScript.Arguments.Item(0)
       
        If objFSO.FolderExists(strFolder) Then
                Set objDictionary = WScript.CreateObject("Scripting.Dictionary")
               
                For Each objFile In objFSO.GetFolder(strFolder).Files
                        If objDictionary.Exists(objFile.Size) Then
                                If objDictionary.Item(objFile.Size) <> "" Then
                                        objFSO.DeleteFile objDictionary.Item(objFile.Size), True
                                        objDictionary.Item(objFile.Size) = ""
                                End If
                               
                                objFSO.DeleteFile objFile.Path, True
                        Else
                                objDictionary.Add objFile.Size, objFile.Path
                        End If
                Next
               
                objDictionary.RemoveAll
               
                Set objDictionary = Nothing
        Else
                WScript.Echo "Folder [" & strFolder & "] not found."
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: " & WScript.ScriptName & " <folder>"
End If

WScript.Quit 0

Путь к папке указываем аргументом скрипта.

Iska 16-07-2011 13:01 1714518

PowerShell:
Код:

param (
    [string]$Folder = "E:\Песочница\0061\*"
)
Get-ChildItem -Path $Folder | `
    Where-Object -FilterScript { -not $_.PSIsContainer } | `
        Group-Object -Property Length | `
            Where-Object -FilterScript { $_.Count -gt 1 } | `
                ForEach-Object -Process {
                    Remove-Item $_.Group
                }


Arsenik77 16-07-2011 14:51 1714571

root221, мне надо чтоб файлы сравнивались между собой (по размеру), а не по конкретному размеру.
Я, в скриптах нуль.
Iska, скрипт полностью удаляет все файлы в папке.

Foreigner 16-07-2011 15:07 1714585

Arsenik77,
Еще вариант:
Код:

@echo off
setlocal enabledelayedexpansion

pushd "c:\test" || goto:eof

for /f "tokens=*" %%i in ('dir /b /a-d') do call:1 "%%i"
for /f "tokens=2 delims==" %%i in ('set todel_') do echo del %%i %%~zi

popd
goto:eof

:1                                                   
if not defined file_%~z1 (

    set "file_%~z1=%1"

) else (

    echo del !file_%~z1! %~z1
    set "file_%~z1=%1"
    set "todel_%~z1=%1"

)

То что красным удалишь после проверки, зеленым исправишь на своё

Arsenik77 16-07-2011 16:11 1714607

Foreigner, не работает, написал "Непредвиденное появление: .jpg" (сравниваю jpg)

megaloman 16-07-2011 16:43 1714623

Задача не очень четко поставлена. Вот решение, удаляем все одинаковые по размеру файлы.
Код:

@Echo Off

Set Otkuda=D:\Delete
Set S1=-1

FOR /F "usebackq delims=" %%f IN (`Dir /B /A:-D /O:SN "%Otkuda%\"`) DO Call :DelSize "%Otkuda%\%%f"
GoTo :Eof

:DelSize
Set S2=%~z1

If %S1% NEQ %S2% (
  Set S1=%S2%
  Set N1=%1
) Else (
  Del %1
  If Exist %N1% Del %N1%
)

Если надо по одному файлу из тех, у которых размер одинаков, оставить, то строку

If Exist %N1% Del %N1%

следует удалить.

ferget 16-07-2011 17:02 1714626

Цитата:

Цитата Arsenik77
"Непредвиденное появление: .jpg" (сравниваю jpg) »

вы так одинаковые изображения хотите удалить?

Foreigner 16-07-2011 17:13 1714632

Arsenik77,

Мой батник удаляет все одинаковые по размеру файлы, независимо от расширения. Если есть например три файла размером 123 и семь файлов размером 321, то он их всех удалит, но оставит файл размером 124, т.к. он один такого размера. В батнике надо указать только папку, в которой сравнивать.

Цитата:

Цитата Arsenik77
Добрый день, нужен батник который удалял одинаковые по размеру файлы в одной папке. »


Arsenik77 16-07-2011 17:38 1714646

root221, Iska, Foreigner, megaloman, - СПАСИБО!
megaloman - работает.

kiripanda 16-07-2011 17:47 1714654

Удаление дубликатов по хешу

Arsenik77 16-07-2011 18:15 1714661

megaloman, поторопился немного, bat-к работает, но как-то выборочно. Проверил на 5000 файлов в папке, батник удаляет, но не всЁ.

Примерно разобрался в чем дело, на файлах где есть в арабские (китайские) или другие не типичные символы батник затыкаеться.
типа XXXXXXXXXXXXX_Штукатурка.jpg
Нужно чтоб батник переименовывал их, во что нибудь типа XXXXXXXXXXXXX_yyyyy.jpg, где XXXXXXXXXXXXX - важные символы, yyyyy неважно.

Батник будет проверять по 100-200 тыс.файлов.

Iska 16-07-2011 20:26 1714728

Цитата:

Цитата Arsenik77
Iska, скрипт полностью удаляет все файлы в папке. »

Arsenik77, какой скрипт из двух? У меня работают оба варианта.

Если Вам нужно искать и удалять дубликаты — то это совсем другой разговор, например, «CloneSpy» или «Duplicate Files Finder», або что-то своё — в зависимости от конкретной задачи и условий применения.

Arsenik77 16-07-2011 20:30 1714733

Iska, работает VBScript, PowerShell не понял как запускать.
Но только надо по одному файлу из тех, у которых размер одинаков, оставить.

Скрипт также работает с "трудными" именами файлов.

megaloman 16-07-2011 20:56 1714744

Попробуйте вариант решения, но при таком большом числе файлов не уверен, как сработает сортировка в Dir. Я попробовал на 50000 файлов, но они небольшого размера
Код:

@Echo Off

Set Otkuda=E:\dddddddd
Set S1=-1

FOR /F "usebackq delims=" %%f IN (`Dir /B /A:-D /O:S "%Otkuda%\"`) DO Call :DelSize "%Otkuda%\%%f"
GoTo :Eof

:DelSize
Set S2=%~z1

If %S1% NEQ %S2% (
  Set S1=%S2%
) Else (
  Del %1
)


Arsenik77 16-07-2011 21:29 1714761

megaloman, работает с нормальным именами файлов, затык идет на таких именах у файло⠨тукатурка.jpg

Foreigner 16-07-2011 21:52 1714777

Arsenik77,
Попробуй такой вариант, правда на большом кол-ве файлов не проверял:
Код:

@echo off
setlocal

pushd "c:\test\folder" || goto:eof
for /f "tokens=*" %%i in ('dir /b /a-d') do call:del "%%~fi"
popd
goto:eof

:del
set "file=%~1"

2>nul 1>nul (

wmic datafile where "path='\\test\\folder\\' and filesize='%~z1' and not name='%file:\=\\%'" call delete

)


Arsenik77 16-07-2011 22:09 1714788

Батник затыкается на не правильных именах файлов, типа :
читать дальше »
16_21217_26+PE%C3%87AS+PRONTAS.JPG.jpg
12809_Гостиная_3.jpg.jpg
12810_Штукатурка_1.jpg.jpg
12811_Штукатурка_2.jpg.jpg

Либо эти файлы (с кривыми именами) надо удалять, либо как-то переименовывать.

Задачу считаю решенной, спасибо megaloman

Iska 18-07-2011 11:18 1714836

В принципе, у меня сработали и пакетный файл Foreigner'а, и пакетный файл megaloman'а.

Цитата:

Цитата Arsenik77
Но только надо по одному файлу из тех, у которых размер одинаков, оставить. »

Ясно. Поскольку изначально в условиях задачи было сказано, что:
Цитата:

Цитата Arsenik77
удалял одинаковые по размеру файлы в одной папке »

то, я хоть и удивился, но сделал именно так, как было сказано :). Причём, коллега megaloman оказался проницательнее — не только удивился, но и усомнился (и, как выяснилось, оказался прав).


Тогда ещё проще (хоть уже и нет необходимости, но приведу код):
Код:

Option Explicit

Dim objFSO
Dim strFolder
Dim objFile
Dim objDictionary
Dim elem


If WScript.Arguments.Count = 1 Then
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        strFolder = WScript.Arguments.Item(0)
       
        If objFSO.FolderExists(strFolder) Then
                Set objDictionary = WScript.CreateObject("Scripting.Dictionary")
               
                For Each objFile In objFSO.GetFolder(strFolder).Files
                        If objDictionary.Exists(objFile.Size) Then
                                objFSO.DeleteFile objFile.Path, True
                        Else
                                objDictionary.Add objFile.Size, objFile.Path
                        End If
                Next
               
                objDictionary.RemoveAll
               
                Set objDictionary = Nothing
        Else
                WScript.Echo "Folder [" & strFolder & "] not found."
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: " & WScript.ScriptName & " <folder>"
End If

WScript.Quit 0

и примерно так (уверен, что подобрал не самый оптимальный вариант):
Код:

param (
    [string]$Folder = "E:\Песочница\0061\*"
)
Get-ChildItem -Path $Folder | `
    Where-Object -FilterScript { -not $_.PSIsContainer } | `
        Group-Object -Property Length | `
            Where-Object -FilterScript { $_.Count -gt 1 } | `
                ForEach-Object -Process {
                    $_.Group | Select-Object -Skip 1 | Remove-Item -Force
                }


amel27 18-07-2011 12:59 1714930

Цитата:

Цитата Arsenik77
Батник затыкается на не правильных именах файлов »

ну это не проблема, вот два различных решения:
Код:

@(
pushd "C:\TEST"
for /f "delims=" %%f in ('dir/b/a-d/os') do @(
  if defined $fz (set/a "$fc=$fz-%%~zf"
    call set "$fc=%%$fc:0=%%"
    if not defined $fc del "%%f")
set "$fz=%%~zf"))

Код:

@(
pushd "C:\TEST"
for /f "delims=" %%f in ('dir/b/a-d/os') do @(
  if defined $fz (SetLocal EnableDelayedExpansion
    if !$fz! equ %%~zf del "%%f"
    EndLocal)
set "$fz=%%~zf"))


Arsenik77 18-07-2011 17:04 1715080

Iska, А можете сделать log файл, сколько файлов было удалено??
Скрипт отлично работает, большое спасибо!!

Iska 19-07-2011 08:35 1715405

Цитата:

Цитата Arsenik77
Iska, А можете сделать log файл, сколько файлов было удалено?? »

Попробуйте так:
Код:

Option Explicit

' IOMode Enum
Const ForReading  = 1
Const ForWriting  = 2
Const ForAppending = 8

' Format Enum
Const TristateUseDefault = -2
Const TristateTrue      = -1
Const TristateFalse      =  0


Dim objFSO
Dim strFolder
Dim objFile
Dim objDictionary
Dim elem

Dim objTS


If WScript.Arguments.Count = 1 Then
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        strFolder = WScript.Arguments.Item(0)
       
        If objFSO.FolderExists(strFolder) Then
                Set objTS = objFSO.OpenTextFile( _
                        objFSO.BuildPath( _
                                objFSO.GetParentFolderName(WScript.ScriptFullName), _
                                objFSO.GetBaseName(WScript.ScriptFullName) & ".log" _
                        ), ForAppending, True, TristateTrue)
               
                objTS.WriteLine
                objTS.WriteLine FormatDateTime(Now())
                objTS.WriteLine
               
                Set objDictionary = WScript.CreateObject("Scripting.Dictionary")
               
                For Each objFile In objFSO.GetFolder(strFolder).Files
                        If objDictionary.Exists(objFile.Size) Then
                                objTS.WriteLine objFile.Path
                                objFSO.DeleteFile objFile.Path, True
                        Else
                                objDictionary.Add objFile.Size, objFile.Path
                        End If
                Next
               
                objDictionary.RemoveAll
               
                Set objDictionary = Nothing
               
                objTS.Close
                Set objTS = Nothing
        Else
                WScript.Echo "Folder [" & strFolder & "] not found."
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: " & WScript.ScriptName & " <folder>"
End If

WScript.Quit 0

Лог-файл будет создан в той же папке [сие, конечно, в корне неправильно] и под тем же именем, что и скрипт, но с расширением «.log».

P.S. Или имена Вам не важны, а нужно именно количество удалённых файлов?

Arsenik77 20-07-2011 06:27 1716078

Цитата:

Цитата Iska
нужно именно количество удалённых файлов »

правильно мыслите,
Цитата:

Цитата Iska
сие, конечно, в корне неправильно »

и это тоже верно, лучше сделать чтоб лог записывался -1 (предыдущую) папку, иногда трудно попасть в папку из-за бооольшого кол-ва файлов.

Iska 20-07-2011 06:59 1716086

Цитата:

Цитата Arsenik77
Цитата:

Цитата Iska
…нужно именно количество удалённых файлов? »

правильно мыслите, »

Примерно так:
читать дальше »
Код:

Option Explicit

' IOMode Enum
Const ForReading  = 1
Const ForWriting  = 2
Const ForAppending = 8

' Format Enum
Const TristateUseDefault = -2
Const TristateTrue      = -1
Const TristateFalse      =  0


Dim objFSO
Dim strFolder
Dim objFile
Dim objDictionary
Dim elem

Dim objTS
Dim lngCount


If WScript.Arguments.Count = 1 Then
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        strFolder = WScript.Arguments.Item(0)
       
        If objFSO.FolderExists(strFolder) Then
                Set objTS = objFSO.OpenTextFile( _
                        objFSO.BuildPath( _
                                objFSO.GetParentFolderName(WScript.ScriptFullName), _
                                objFSO.GetBaseName(WScript.ScriptFullName) & ".log" _
                        ), ForAppending, True, TristateTrue)
               
                objTS.WriteLine
                objTS.WriteLine FormatDateTime(Now())
                objTS.WriteLine
               
                Set objDictionary = WScript.CreateObject("Scripting.Dictionary")
               
                lngCount = 0
               
                For Each objFile In objFSO.GetFolder(strFolder).Files
                        If objDictionary.Exists(objFile.Size) Then
                                objTS.WriteLine objFile.Path
                                objFSO.DeleteFile objFile.Path, True
                                lngCount = lngCount + 1
                        Else
                                objDictionary.Add objFile.Size, objFile.Path
                        End If
                Next
               
                objDictionary.RemoveAll
               
                Set objDictionary = Nothing
               
                objTS.WriteLine
                objTS.WriteLine "Total delete: " & lngCount & " file(s)"
               
                objTS.Close
                Set objTS = Nothing
        Else
                WScript.Echo "Folder [" & strFolder & "] not found."
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: " & WScript.ScriptName & " <folder>"
End If

WScript.Quit 0


Цитата:

Цитата Arsenik77
лучше сделать чтоб лог записывался -1 (предыдущую) папку, »

Я не понял Вашу мысль. Поясните, пожалуйста, на примере.

Arsenik77 20-07-2011 09:24 1716151

Цитата:

Цитата Iska
Примерно так: »

нет список файлов не надо вообще, иногда он может быть ооочень большим.
Последний раз Ваш скрипт обработал 330 тыщ.файлов, удалив порядка 160 тыщи файлов.
Хотя если можно то ее можно оставить, включая или отключая её через ключ (параметр).
Можно добавить в логе писал: Total delete: YY file(s) из XXX файлов.

Цитата:

Цитата Iska
Я не понял Вашу мысль. Поясните, пожалуйста, на примере. »

вы уже реализовали её.

Iska 20-07-2011 13:06 1716294

Цитата:

Цитата Arsenik77
Хотя если можно то ее можно оставить, включая или отключая её через ключ (параметр).

Можно добавить в логе писал: Total delete: YY file(s) из XXX файлов. »

Сделаем, но позже.

Iska 08-08-2011 04:53 1727593

Arsenik77, сделал:
читать дальше »
Код:

<?xml version="1.0" encoding="windows-1251" standalone="yes" ?>
<package>
        <job>
        <?job error="True" Debug="True" ?>
                <runtime>
                        <description>Description:  Delete 'duplicate' files in folder by equal size</description>
                       
                        <unnamed
                                name      = "Folder"
                                helpstring = "Path to folder to scan"
                                many      = "False"
                                required  = "True"
                        />
                        <named
                                name      = "IncludeNames2Log"
                                helpstring = "Include paths of deleted files to log"
                                type      = "Simple"
                                required  = "False"
                        />
                        <example>
Example:      Script.wsf "c:\Temp" [/IncludeNames2Log]</example>
                </runtime>
                <reference                object="Scripting.FileSystemObject" />
                <object id="objFSO"        progid="Scripting.FileSystemObject" />
                <object id="objDictionary" progid="Scripting.Dictionary" />
               
                <script language="VBScript">
                        <![CDATA[
                                Option Explicit
                               
                                With WScript.Arguments
                                        Select Case .Count
                                                Case 1
                                                        If .Unnamed.Count = 1 Then
                                                                WScript.Quit Working(.Unnamed.Item(0), False)
                                                        End If
                                                Case 2
                                                        If .Unnamed.Count = 1 And .Named.Count = 1 Then
                                                                If .Named.Exists("IncludeNames2Log") Then
                                                                        WScript.Quit Working(.Unnamed.Item(0), True)
                                                                End If
                                                        End If
                                                Case Else
                                                        ' Nothing to do
                                        End Select
                                End With
                               
                                WScript.Echo "Error in arguments"
                                WScript.Echo
                               
                                WScript.Arguments.ShowUsage()
                                WScript.Quit 1
                                '=========================================================================
                               
                                '=========================================================================
                                Function Working(strFolder, boolIncludeNames2Log)
                                        Dim collFiles
                                        Dim objFile
                                        Dim elem
                                       
                                        Dim objTS
                                       
                                        Dim lngTotalCount
                                        Dim lngDeleteCount
                                       
                                        If objFSO.FolderExists(strFolder) Then
                                                Set objTS = objFSO.OpenTextFile( _
                                                        objFSO.BuildPath( _
                                                                objFSO.GetParentFolderName(WScript.ScriptFullName), _
                                                                objFSO.GetBaseName(WScript.ScriptFullName) & ".log" _
                                                        ), ForAppending, True, TristateTrue)
                                               
                                                objTS.WriteLine
                                                objTS.WriteLine FormatDateTime(Now())
                                                objTS.WriteLine
                                               
                                                Set collFiles = objFSO.GetFolder(strFolder).Files
                                               
                                                lngDeleteCount = 0
                                                lngTotalCount  = collFiles.Count
                                               
                                                For Each objFile In collFiles
                                                        If objDictionary.Exists(objFile.Size) Then
                                                                If boolIncludeNames2Log Then
                                                                        objTS.WriteLine objFile.Path
                                                                End If
                                                               
                                                                objFSO.DeleteFile objFile.Path, True
                                                                lngDeleteCount = lngDeleteCount + 1
                                                        Else
                                                                objDictionary.Add objFile.Size, objFile.Path
                                                        End If
                                                Next
                                               
                                                Set collFiles = Nothing
                                               
                                                objDictionary.RemoveAll
                                               
                                                objTS.WriteLine
                                                objTS.WriteLine "Deleted " & lngDeleteCount & " of " & lngTotalCount & " file(s)"
                                               
                                                objTS.Close
                                                Set objTS = Nothing
                                               
                                                Working = 0
                                        Else
                                                WScript.Echo "Folder [" & strFolder & "] not found."
                                                WScript.Echo
                                               
                                                Working = 2
                                        End If
                                End Function
                                '=========================================================================
                        ]]>
                </script>
        </job>
</package>


Приведённый код сохранить в файл с расширением «.wsf» в кодировке ANSI (Windows-1251).


Время: 04:52.

Время: 04:52.
© OSzone.net 2001-