Удаление одинаковых файлов (по MD5/размеру)

Обсуждение программ nnCron и nnCron LITE

Удаление одинаковых файлов (по MD5/размеру)

Postby Morituruz » Wed, 05 Sep 2012, 13:55

1. Выбираем, каким способом будем устанавливать идентичность файлов: по MD5 хешу или по размеру.
2. Вставляем в окошко путь и маску файлов, например c:\WINDOWS\*
Image
3. Смотрим в текстовом редакторе на список файлов (группы одинаковых файлов отделены переносом строки)
4. Удаляем одинаковые файлы.

Для работы требуется плагин Автостроки и Lists.spf

Code: Select all
<%
\ разрешение экрана
: xRes
GetDesktopSize DROP
;
: yRes
GetDesktopSize SWAP DROP
;
: mRes
GetDesktopSize + 2 /
;
CREATE soh_zstr 1 C,  0 C,
: soh soh_zstr 1 ;
: StringGetPos { a1 u1 a2 u2 -- pos}
a1 u1 a2 u2 SEARCH IF DROP a1 - 1+ ELSE 2DROP 0 THEN
;
: StringReplace { a1 u1 a2 u2  a3 u3 \ rest a4 u4 buf -- a u }  \ Заменить в строке 1 подстроку 2 на строку 3, на стеке останется измененая строка
  AT buf TO a4
  a1 u1
  BEGIN OVER SWAP a2 u2 SEARCH WHILE
    TO rest SWAP 2DUP - a4 u4 2SWAP S+ TO u4 TO a4
    a3 u3 a4 u4 2SWAP S+ TO u4 TO a4
    rest u2 /STRING
  REPEAT
  a4 u4 2SWAP S+
  ROT DROP
;

%>

#( delete_duplicate_files_MD5-size
\ 9:43 03.09.2012
NoLog
NoActive
SingleInstance

USER-CREATE ddm_name 255 USER-ALLOT
USER-CREATE ddm_method 255 USER-ALLOT
STRING-LIST: list_of_md5
STRING-LIST: list_of_duplicate_files
: FILE-MD5   \ ( a u -- a1 u1 )
  PAD 256 ERASE
  PAD ROT ROT MD5File DROP
  PAD MD5String
;
Action:
4096 32 3 + + S" Поиск дубликатов" DROP
" Каким способом ищем:|nДа — по хешу, нет — по размеру"
DROP 0 MessageBoxA
CASE
6 OF S" по хешу" ddm_name PLACE S" FILE-MD5" ddm_method PLACE ENDOF
7 OF S" по размеру" ddm_name PLACE S" FSIZE DOUBLE>S" ddm_method PLACE ENDOF
DUP OF EXIT ENDOF
ENDCASE
WIN-INPUT-TEXT: "Поиск одинаковых файлов (%ddm_name COUNT%)" "Путь с маской:" "" 0
IF
   EXIT
THEN
mRes 10 / RANDOM 20 + DUP HINT-POS
0x28A432 0x000000 HINT-COLOR
HINT: "Поиск одинаковых %ddm_name COUNT% файлов..."
RECURSIVE SKIPERRORS
FOR-FILES
   IS-DIR? NOT
   IF
      FOUND-FULLPATH ddm_method COUNT EVALUATE
      \ флаг, чтобы понять нашлось в списке или нет:
      TRUE
      list_of_md5(
         2 PICK 2 PICK NODE@ 2DUP soh StringGetPos 1 - MIN COMPARE 0=
         IF \ есть в списке, т.е. повтор:
            NODE@ 2DUP soh StringGetPos /STRING soh S+ FOUND-FULLPATH S+ list_of_duplicate_files!
            \ инвертируем флаг:
            INVERT
            LIST-EXIT
         THEN
      )list_of_md5
      IF
         \ не нашлось, значит уникальный:
         soh S+ FOUND-FULLPATH S+ list_of_md5!
      ELSE
         2DROP
      THEN
   THEN
;FOR-FILES
HINT-OFF
4096 32 4 + + " Поиск одинаковых %ddm_name COUNT% файлов" DROP
" Уникальных %ddm_name COUNT% файлов: %list_of_md5# N>S%|nКопий: %list_of_duplicate_files# N>S%|nВывести список?"
DROP 0 MessageBoxA 6 =
IF
   S" TEMP" ENV 2DUP DUP 1 - /STRING S" \" COMPARE
   IF
      \ на случай, если в системной переменной нет обратной черты:
      S" \" S+
   THEN
   TempFile S+ S" .txt" S+
   ""
   list_of_duplicate_files(
      \ есть ли такой оригинал в строке
      2DUP NODE@ 2DUP soh StringGetPos 1 - MIN StringGetPos
      IF
         NODE@ 2DUP soh StringGetPos 1 - MIN \ строка ориг. файла
         NODE@ soh " |n" StringReplace \ ориг. + копия через перенос и таб.
         StringReplace \ заменяем ориг. строку на оригинальную + копия через таб.
      ELSE
         NODE@ soh " |n" StringReplace CRLF CRLF S+ S+ S+
      THEN
   )list_of_duplicate_files
   3 PICK 3 PICK FWRITE
   \ открываем созданный txt
   START-APP
THEN
4096 32 4 + + " Поиск одинаковых %ddm_name COUNT% файлов" DROP
" Удалить одинаковые %ddm_name COUNT% файлы (%list_of_duplicate_files# N>S% шт.)?"
DROP 0 MessageBoxA 6 =
IF
   list_of_duplicate_files(
      NODE@ 2DUP soh StringGetPos /STRING FDELETE
   )list_of_duplicate_files
   4096 32 + " Поиск одинаковых %ddm_name COUNT% файлов" DROP
   " Одинаковые %ddm_name COUNT% файлы удалены"
   DROP 0 MessageBoxA DROP
THEN
list_of_md5 LIST-FREE
list_of_duplicate_files LIST-FREE
)#

Last edited by Morituruz on Mon, 24 Sep 2012, 18:33, edited 3 times in total.
User avatar
Morituruz
 
Posts: 727
Joined: Sun, 14 Oct 2007, 01:51

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby SeMa » Thu, 13 Sep 2012, 17:07

Moriturus wrote:Для работы требуется плагин "Автостроки".
ещё lists.spf.

ещё "ругается" на строку с mRes
Code: Select all
mRes 10 / RANDOM 20 + DUP HINT-POS

Вопрос. Дубликаты сравниваются с первым по маске файлом? И какой порядок сортировки файлов? От этого зависит, какой файл будет признан образцом.
Компьютер ─ устройство, разработанное для ускорения и автоматизации человеческих ошибок
User avatar
SeMa
 
Posts: 637
Joined: Fri, 15 Apr 2005, 12:49
Location: Украина

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby Morituruz » Fri, 14 Sep 2012, 08:38

SeMa wrote:ещё "ругается" на строку с mRes

Спасибо, обновил первый пост (слова для определения разрешения экрана).
SeMa wrote:Вопрос. Дубликаты сравниваются с первым по маске файлом? И какой порядок сортировки файлов? От этого зависит, какой файл будет признан образцом.

Дубликаты сравниваются с теми файлами, что уже найдены, т.е. порядок сортировки такой же как в файловой системе — кто первый нашёлся, тот и оригинал. Кстати, в списке в текстовом редакторе оригинал идёт первым, а «дубликаты» идут после, но в обратном порядке.
User avatar
Morituruz
 
Posts: 727
Joined: Sun, 14 Oct 2007, 01:51

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby SeMa » Mon, 24 Sep 2012, 17:36

Moriturus wrote:Спасибо, обновил первый пост

Прошу прощения за задержку проверки задачи.
Нет определения StringReplace.
Компьютер ─ устройство, разработанное для ускорения и автоматизации человеческих ошибок
User avatar
SeMa
 
Posts: 637
Joined: Fri, 15 Apr 2005, 12:49
Location: Украина

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby VoidVolker » Mon, 24 Sep 2012, 18:14

Поиск решает.
Code: Select all
: StringReplace { a1 u1 a2 u2  a3 u3 \ rest a4 u4 buf -- a u }  \ Заменить в строке 1 подстроку 2 на строку 3, на стеке останется измененая строка
  AT buf TO a4
  a1 u1
  BEGIN OVER SWAP a2 u2 SEARCH WHILE
    TO rest SWAP 2DUP - a4 u4 2SWAP S+ TO u4 TO a4
    a3 u3 a4 u4 2SWAP S+ TO u4 TO a4
    rest u2 /STRING
  REPEAT
  a4 u4 2SWAP S+
  ROT DROP
;
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby Morituruz » Mon, 24 Sep 2012, 18:34

Вечная проблема :( Обновил!
User avatar
Morituruz
 
Posts: 727
Joined: Sun, 14 Oct 2007, 01:51

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby SeMa » Tue, 25 Sep 2012, 16:11

VoidVolker wrote:Поиск решает.
Как-то забылось :? . Много раз видел, но себе на записал.

Moriturus wrote:Обновил!
1й запуск задачи.
Всё отрабатывает. После последнего нажатия кнопки вываливается
delete_duplicate_files_MD5-size: Internal error. Параметр задан неверно.
2й+ запуск.
После ввода пути вываливается
delete_duplicate_files_MD5-size: Internal error. Error # -1073741819
На экране остался зелёный хинт.
Перечитали кронтаб. Повторяется снова с 1-го запуска.
25.09.12 13:28:22 1208 D:\nnCron\_nncron.tab
25.09.12 13:28:22 1208 D:\nnCron\_test.tab
25.09.12 13:32:08 4228 delete_duplicate_files_MD5-size: Internal error. Параметр задан неверно.
25.09.12 13:32:38 5216 delete_duplicate_files_MD5-size: Internal error. Error # -1073741819
25.09.12 13:35:30 1604 delete_duplicate_files_MD5-size: Internal error. Error # -1073741819
25.09.12 13:35:50 1208 Load crontab
25.09.12 13:35:50 1208 D:\nnCron\_nncron.tab
25.09.12 13:35:50 1208 D:\nnCron\_test.tab
25.09.12 13:36:26 3556 delete_duplicate_files_MD5-size: Internal error. Параметр задан неверно.
25.09.12 13:36:40 3656 delete_duplicate_files_MD5-size: Internal error. Error # -1073741819

В nncron.out при 2м+ запуске добавляется
EXCEPTION! CODE:C0000005 ADDRESS:4B22CC WORD:2@ REGISTERS:
21AFBE8 94 1E ED 01 0C 00 00 00 B0 89 EB 01 14 E5 90 7C ”.н.....°‰л..еђ|
21AFBF8 02 00 00 00 04 00 00 00 78 EF 1A 02 CC 22 4B 00 ........xп..М"K.
21AFC08 1B 00 00 00 12 02 01 00 18 FE 1A 02 23 00 00 00 .........ю..#...
USER DATA: 1ED1E94 HANDLER: 21AEFC0 RETURN STACK:
21AEF78 : 522101 NodeS@
21AEF7C : 520885 NODE>@
21AEF80 : 5209A8 NODE@
21AEF84 : 531D3A list_of_duplicate_files#@
21AEF88 : 5207C8 FOR-LIST
21AEF8C : 0 <not found>
21AEF90 : 4B2C48 (LocalsExit)
21AEF94 : 4 <not found>
21AEF98 : 531D21 list_of_duplicate_files#@
21AEF9C : 531DBB list_of_duplicate_files#@
21AEFA0 : 4CD394 FF-PASS-FILEs
21AEFA4 : 4CD404 FF-PASS-FILEs
21AEFA8 : 0 <not found>
21AEFAC : 0 <not found>
21AEFB0 : 4CD60E (FOR-FILES)
21AEFB4 : 0 <not found>
21AEFB8 : 531DFB list_of_duplicate_files#@
21AEFBC : 4B4AD3 CATCH
21AEFC0 : 0 <not found>
Компьютер ─ устройство, разработанное для ускорения и автоматизации человеческих ошибок
User avatar
SeMa
 
Posts: 637
Joined: Fri, 15 Apr 2005, 12:49
Location: Украина

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby Morituruz » Tue, 25 Sep 2012, 16:52

SeMa
Я проверил на почти чистом nncron, работает.
У вас плагин lists самый свежий? Со свежим у меня что-то совсем ничего не работало, я на предыдущей версии сижу, VoidVolker сказал локализовывать, да всё времени нет.
Вот стабильная версия плагина, если есть возможность, проверьте на ней:
Code: Select all
\ Файл: lists.spf
\ Автор: VoidVolker
\ Дата: 30/01/2012 21:00
\ Описание: Расширяемые односвязные списки с глобальным или локальным для потока выделением памяти.
\ Каждый список определяется заголовком, который содержит служебные параметры, являющиеся необходимой частью интерфейса для работы со списками. Слово "расширяемые" означает, что можно использовать в качестве значения списка адрес пользовательской структуры и записать в заголовок списка методы работы с этой структурой. При этом стандартные методы станут использовать эти самые пользовательские методы.

 \ Список состоит из "заголовка" и "узлов":
 \ - в заголовке хранятся первый и последний узлы списка;
 \ - в узле в первой ячейке хранится адрес на следующий узел и пользовательское значение во второй ячейке.
\ --------------------------------------------------------------------------
\ Условные обозначения:
\ list - список, фактически адрес его заголовка
\ node - узел списка, адрес
\ value - значение узла списка, число; или строка в случае строкового списка
\ i - индекс, число
\ xt - выполнимый токен слова, адрес, предназначенный для передачи слову EXECUTE
\ -> - стековый коментарий относится к входному потоку
\ " name" - имя, отделенное разделителями
\ | - "или", указывает, что на стеке может быть одно из двух(нескольких) значений

\ Слова:
\ FOR-LIST \ ( list xt -- ) \ Для каждого узла списка list выполнить xt
\ LIST-EXIT \ ( -- ) \ Закончить просмотр списка.

\ LIST( \ ( list -- ) \ Выполнить для каждого узла списка list код, ограниченный словом )LIST . Допускает вложенность. Только для режима компиляции.
\ )LIST \ ( -- ) \ Закончить описание кода, начатого словом LIST( . Только для режима компиляции.

\ NODE>@ \ ( node list -- value ) \ Получить значение узла node списка list
\ NODE>! \ ( value node list -- ) \ Записать значение value в узел node списка list
\ VAL>= \ ( value value list -- ? ) \ Сравнить два значения списка list
\ VAL-DROP> \ ( value list -- ) \ Удалить значение списка list
\ VAL-DUP> \ ( value list -- value value) \ Дублировать значение списка list
\ NODE># \ ( node list -- i|-1 ) \ Вычислить индекс узла node списка list. Вернуть -1 в случае отсутствия узла в списке.

\ NODE \ ( -- node ) \ Получить адрес текущего узла списка. Только внутри цикла LIST( )LIST
\ NODE@ \ ( -- NodeValue ) \ Получить значение текущего узла списка. Только внутри цикла LIST( )LIST
\ NODE! \ ( NodeValue -- ) \ Записать значение со стека в текущий узел списка. Только внутри цикла LIST( )LIST
\ VAL= \ ( value1 value2 -- ? ) \ Сравнить два значения. Только внутри цикла LIST( )LIST
\ VAL-DROP \ ( value -- ) \ Удалить значение со стека. Только внутри цикла LIST( )LIST
\ VAL-DUP \ ( value -- value ) \ Дублировать значение на стеке. Только внутри цикла LIST( )LIST

\ LIST> \ ( list -- ) \ Пошаговый цикл. Перейти к следующему узлу списка. Работает замкнуто - после последнего элемента будет ноль, затем снова первый узел. Слово предназначено для применения внутри пользовательских циклов, но прекрасно работает и в цикле LIST( )LIST
\ LIST@ \ ( list -- nodevalue|0 ) \ Получить текущее значение пошагового цикла списка. При переходе через конец списка результатом будет ноль и только потом первый узел
\ LIST@> \ ( list -- nodevalue ) \ Получить текущее значение пошагового цикла и перейти к следующему узлу списка. Синоним фразы list LIST@ list LIST@>
\ LIST-- \ ( list -- ) \ Инициализировать пошаговый цикл списка list первым узлом.

\ NDEL \ ( -- ) \ Удалить текущий узел списка. Только внутри цикла LIST( )LIST
\ LIST-FREE \ ( list -- ) \ Полностью очистить список.
\ NODE-DEL \ ( value list --) Удалить первый узел, который содержит указанное значение
\ LIST? \ ( value list -- node|0) Проверить, хранится ли указанное значение в списке. Возвращает адрес узла, в котором хранится значение или 0, если значение не обнаружено.

\ !LIST \ ( value list -- ) \ Добавить в начало списка значение value
\ LIST! \ ( value list -- ) \ Добавить в конец списка значение value
\ LIST#! \ ( val_1 ... val_n n list -- ) \ Добавить поочередно n значений со стека в конец списка list. Значения добавляются начиная с вершины стека в конец списка в порядке очереди.
\ #!LIST \ ( val_1 ... val_n n list -- ) \ Добавить поочередно n значений со стека в начало списка list. Значения добавляются начиная с вершины стека в начало списка в порядке очереди.

\ LIST[ \ ( list -- list-handle list-pos ) \ Начать добавление значений в список.
\ ]LIST \ ( list-handle list-pos x*i -- ) \ Закончить добавление значений в список. Слово вычисляет число значений, оказавшихся на стеке после слова LIST[ и добавляет их все в начало списка по порядку.

\ LIST# \ ( list -- i ) \ Посчитать число узлов в списке list
\ LIST#> \ ( i list -- node ) \ Получить узел node списка list под номером i
\ LIST#@ \ ( i list -- value ) \ Получить значение узла списка list

\ Статические списки
\ LIST: \ ( " name" -> ) \ Создать список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Слово является VALUE-переменной. В задачах добавлять и читать значения из списка следует в разделе Action:, не раньше (*).
\ GLOBAL-LIST: \ ( " name" -> ) \ Создать глобальный список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Список доступен для всех потоков. Слово является VALUE-переменной. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.

\ STRING-LIST: \ ( " name" -> ) \ Создать строковый список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Слово является VALUE-переменной. В задачах добавлять и читать значения из списка следует в разделе Action:, не раньше(*).
\ GLOBAL-STRING-LIST: \ ( " name" -> ) \ Создать глобальный строковый список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Список доступен для всех потоков. Слово является VALUE-переменной. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.
\ (*) Это связано с тем, что перечитыванием кронтабов занимается отдельный поток. Соответственно до раздела Action: - один поток, а после, при выполнении задачи, - это уже будет другой поток. У глобальных списков таких ограничений нет.

\ При создании именованного статического списка автоматически создаются следующие слова для быстрой работы со списком:
\ : listname( POSTPONE listname [COMPILE] LIST( ; IMMEDIATE
\ : )listname [COMPILE] )LIST ; IMMEDIATE
\ : listname> listname LIST> ;
\ : listname@ listname LIST@ ;
\ : listname@> listname LIST@> ;
\ : listname-- listname LIST-- ;
\ : listname? listname LIST? ;
\ : !listname listname !LIST ;
\ : listname! listname LIST! ;
\ : listname#! listname LIST#! ;
\ : #!listname listname #!LIST ;
\ : listname[ listname LIST[ ;
\ : ]listname ]LIST ;
\ : listname# listname LIST# ;
\ : listname#> listname LIST#> ;
\ : listname#@ listname LIST#@ ;

\ Динамические списки
\ LIST \ ( -- list ) \ Создать список. Для заголовка списка выделяется память из хипа: такой список можно уничтожить.
\ GLOBAL-LIST \ ( -- list ) \ Создать глобальный список. Для заголовка списка выделяется память из глобального хипа: такой список можно уничтожить. Список доступен для всех потоков. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.

\ STRING-LIST \ ( -- list ) \ Создать строковый список. Для заголовка списка выделяется память из хипа: такой список можно уничтожить. Работает исколючительно со строками. Динамически выделяет и освобождает для строк память.
\ GLOBAL-STRING-LIST \ ( -- list ) \ Создать глобальный строковый список. Для заголовка списка выделяется память из глобального хипа: такой список можно уничтожить. Список доступен для всех потоков. Работает исколючительно со строками. Динамически выделяет и освобождает для строк память. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.

\ LIST-DEL \ ( list -- ) \ Уничтожить список и все его содержимое. Только для динамических списков.

\ --------------------------------------------------------------------------
\ Примеры использования списков

\ Создаем список:
\ LIST: list

\ Добавляем в него группу значений:
\ list[ 1 2 3 4 5 ]list

\ Вот так можно распечатать:
\ : list. list( NODE@ . )list CR ;
\ Или вот так:
\ : list.1 list LIST( NODE@ . )LIST CR ;
\ Результат в обоих случаях будет одинаковый:
\ 1 2 3 4 5
\ Ok

\ А вот немного другой вариант:
\ : list#. 0 DO list@ list> . LOOP CR ;
\ И еще один вариант:
\ : list.2 list( NODE@ . NODE@ 3 = IF LIST-EXIT THEN )list CR ;

\ Результат:
\ 3 mylist#.
\ 1 2 3
\ Ok

\ Аналогично и со строковыми списками(*):
\ STRING-LIST: s
\ s[ " Строка" " Текст" " Имя" ]s
\ : s. s( NODE@ TYPE CR )s ;
\ Результат:
\ s.
\ Строка
\ Текст
\ Имя
\ Ok

\ (*) При использовании этого метода заполнения списка строками, в режиме интерпретации следует
\ распологать все строки в одной строке, т.к. при переходе интерпретатора к следующей строке
\ предыдущие строки будут стерты. Это особенность работы интерпретатора - он обрабатывает файл построчно.
\ А вот в режиме компиляции такой проблемы нет, т.к. строка сразу сохраняется в память системы.
\ Если строк много, то следует хранить их в файле и загружать в список построчным чтением файла. Например в цикле READ-BY-LINE

\ А вот так можно работать с деревьями и динамическими списками:
\ LIST: Tree
\ Tree[
 \ STRING-LIST DUP LIST[ " Ветвь дерева 1" " Лист 1 ветви 1" " Лист 2 ветви 1" ]LIST
 \ STRING-LIST DUP LIST[ " Ветвь дерева 2" " Лист 1 ветви 2" " Лист 2 ветви 2" ]LIST
\ ]Tree
\ : Tree. Tree( NODE@ LIST( NODE@ TYPE CR )LIST CR )Tree CR ;
\ : TreeFree Tree( NODE@ LIST-DEL )Tree Tree LIST-FREE ;

\ Tree.
\ Ветвь дерева 1
 \ Лист 1 ветви 1
 \ Лист 2 ветви 1

\ Ветвь дерева 2
 \ Лист 1 ветви 2
 \ Лист 2 ветви 2
 \ Ok

\ После работы с деревом освободим его:
\ TreeFree

\ --------------------------------------------------------------------------

 \ value - пользовательское значение, может занимать различное число ячеек для разных списков
 \ list - список, фактически адрес заголовка списка
 \ node - узел списка
 \ nodevalue - значение, хранящееся в узле списка
 \ параметр:значение - обозначает какой-то параметр с новым значением, например адрес в памяти и его содержимое node:last-node или стек возвратов и его содержимое R: list node

\ --------------------------------------------------------------------------

MODULE: LIST_MODULE

 \ *** Код для спф
 \ REQUIRE { lib/ext/locals.f \ }
 \ : ON -1 SWAP ! ;
 \ : OFF 0! ;
 \ : [NONAME
 \ ?COMP HERE BRANCH, >MARK 1
 \ HERE
 \ ; IMMEDIATE
 \ : NONAME]
 \ ?COMP RET,
 \ >R >RESOLVE
 \ R> POSTPONE LITERAL
 \ ; IMMEDIATE
 \ WINAPI: GlobalAlloc KERNEL32.DLL
 \ WINAPI: GlobalFree KERNEL32.DLL
 \ : GLOBAL-ALLOCATE ( bytes -- address ior)
 \ 0x40 GlobalAlloc DUP IF 0 ELSE GetLastError THEN ;
 \ : GLOBAL-FREE ( address - ior) GlobalFree ;

 \ *** Временный буфер
 \ Динамически выделяемый буфер для хранения служебных параметров в циклическом итераторе LIST( )LIST
 USER-VALUE ListSets
 0
 CELL -- -LSNode \ Текущий узел списка
 CELL -- -LSPNode \ Предыдущий узел списка
 CELL -- -LSList \ Заголовок спика
 CELL -- -LSDo? \ Флаг, разрешающий работу итератора
 CONSTANT /ListSets

 \ *** Заголовок списка
 0
 CELL -- -ListFirstNode \ Первый узел списка
 CELL -- -ListLastNode \ Последний узел списка
 CELL -- -ListNode \ Текущий узел списка, необходимо для пошагового итератора
 CELL -- -ListValCells \ Число ячеек для одного значения, используется только в LIST[ ... ]LIST
 \ А вот это пускай будут методы списка
 \ * Память
 CELL -- -ListAllocate \ Выделение памяти для списка ( size -- addr ior )
 CELL -- -ListFree \ Освобождение памяти, занятой списком ( addr -- ior )
 CELL -- -ListNodeFree \ Освобождение памяти, занятой узлом списка ( node -- ior )
 \ После стекового комментария указано слово, выполняемое по-умоланию.
 \ Зачем именно так? А затем, что теперь мы можем просто записать нужные токены в заголовок списка и он будет работать с другими типами данных без изменения синтаксиса. Например работать с двойными(тройным) ячейками.
 \ * Элементы списка
 CELL -- -ListNode@ \ Получение значения ( node -- value ) val@
 CELL -- -ListNode! \ Запись значения ( value node list* -- ) val! (*) Заголвок списка нужен для доступа к методам памяти списка для строковых списков или других видов списка
 \ * Значение элемента
 CELL -- -ListVal= \ Сравнение значения ( value1 value2 -- ? ) =
 CELL -- -ListValDrop \ Удаление значения ( value -- ) DROP
 CELL -- -ListValDup \ Дублирование значения ( value -- value value ) DUP
 CONSTANT /ListHeader

 \ *** Извлечение и запись значения в узлы списка
 : val@ \ ( node -- value )
 CELL+ @ ;
 : val! \ ( value node list* -- )
 DROP CELL+ !
 ;

 \ *** Заголовки списков с готовыми параметрами
 CREATE GlobalListHeader 0 , 0 , 0 , 1 ,
 ' GLOBAL-ALLOCATE ,
 ' GLOBAL-FREE ,
 ' GLOBAL-FREE ,
 ' val@ ,
 ' val! ,
 ' = ,
 ' DROP ,
 ' DUP ,

 CREATE ListHeader 0 , 0 , 0 , 1 ,
 ' ALLOCATE ,
 ' FREE ,
 ' FREE ,
 ' val@ ,
 ' val! ,
 ' = ,
 ' DROP ,
 ' DUP ,

 \ *** Слова для быстрого доступа к параметрам списка.
 : PNode ListSets -LSPNode ;
 : PNode! ListSets -LSPNode ! ;
 : PNode@ ListSets -LSPNode @ ;
 : List ListSets -LSList ;
 : List! ListSets -LSList ! ;
 : List@ ListSets -LSList @ ;
 : Do? ListSets -LSDo? @ ;
 : DoOn ListSets -LSDo? ON ;
 : DoOff ListSets -LSDo? OFF ;

EXPORT

 \ *** Циклический итератор FOR-LIST
 : FOR-LIST { xt -- } \ ( list xt -- ) \ Для каждого узла списка list выполнить xt
 \ Динамическое выделение буфера для параметров списка позволяет использовать вложенность
 \ Все параметры списка хранятся во временном буфере
 ListSets >R \ Сохраняем предыдущий буфер
 /ListSets ALLOCATE THROW TO ListSets \ Выделяем новый буфер
 DUP List! \ Сохраняем идентификатор списка
 DoOn \ Разрешаем итерацию
 DUP PNode! \ Предыдущим узлом устанавливаем заголовок списка
 @ ListSets ! \ Сохраняем первый узел списка во временный буфер
 BEGIN ListSets @ Do? AND WHILE \ Запускаем цикл по всем узлам
 xt EXECUTE \ Выполняем токен
 ListSets @ DUP PNode! \ Сохраняем текущий узел как предыдущий
 @ ListSets ! \ Получаем следующий узел
 REPEAT
 ListSets FREE THROW \ Освобождаем текущий буфер
 R> TO ListSets \ Восстанавливаем предыдущий буфер
 ;

 : LIST-EXIT \ ( -- ) \ Закончить просмотр списка.
 ListSets -LSDo? OFF \ Синоним DoOff
 ;

 \ *** Непрерывный цикл LIST( )LIST
 : LIST( \ ( list -- ) \ Выполнить для каждого узла списка list код, ограниченный словом )LIST . Допускает вложенность. Только для режима компиляции.
 POSTPONE [NONAME
 ; IMMEDIATE

 : )LIST \ ( -- ) \ Закончить описание кода, начатого словом LIST( . Только для режима компиляции.
 POSTPONE NONAME]
 POSTPONE FOR-LIST
 ; IMMEDIATE

 \ *** Методы списка
 : NODE>@ \ ( node list -- value ) \ Получить значение узла node списка list
 -ListNode@ @ EXECUTE ;
 : NODE>! \ ( value node list -- ) \ Записать значение value в узел node списка list
 DUP -ListNode! @ EXECUTE ;
 : VAL>= \ ( value value list -- ? ) \ Сравнить два значения списка list
 -ListVal= @ EXECUTE ;
 : VAL-DROP> \ ( value list -- ) \ Удалить значение списка list
 -ListValDrop @ EXECUTE ;
 : VAL-DUP> \ ( value list -- value value) \ Дублировать значение списка list
 -ListValDup @ EXECUTE
 ;


 \ *** Быстрые методы LIST( )LIST
 : NODE \ ( -- Node ) \ Получить адрес текущего узла списка. Только внутри цикла LIST( )LIST
 ListSets @
 ;

 : NODE@ \ ( -- NodeValue ) \ Получить значение текущего узла списка. Только внутри цикла LIST( )LIST
 ListSets @ List@ NODE>@ ;
 : NODE! \ ( NodeValue -- ) \ Записать значение со стека в текущий узел списка. Только внутри цикла LIST( )LIST
 ListSets @ List@ NODE>! ;
 : VAL= \ ( value1 value2 -- ? ) \ Сравнить два значения. Только внутри цикла LIST( )LIST
 List@ VAL>= ;
 : VAL-DROP \ ( value -- ) \ Удалить значение со стека. Только внутри цикла LIST( )LIST
 List@ VAL-DROP> ;
 : VAL-DUP \ ( value -- value ) \ Дублировать значение на стеке. Только внутри цикла LIST( )LIST
 List@ VAL-DUP>
 ;

 : NODE># \ ( node list -- i|-1 ) \ Вычислить индекс узла node списка list. Вернуть -1 в случае отсутствия узла в списке
 0 ROT ROT 0 SWAP \ 0 node 0 list
 LIST(
 OVER NODE =
 IF
 LIST-EXIT
 2>R DROP -1 2R>
 ELSE
 1+
 THEN
 )LIST NIP
 SWAP IF ELSE DROP -1 THEN
 ;

 \ *** Пошаговый цикл
 : LIST> \ ( list -- ) \ Пошаговый цикл. Перейти к следующему узлу списка. Работает замкнуто - после последнего элемента будет ноль, затем снова первый узел. Слово предназначено для применения внутри пользовательских циклов, но прекрасно работает в цикле LIST( )LIST
 \ Это слово требует при создании списка установку текущего узла списка одновременно с первым элементом (решено в слове !LIST )
 \ Возможный конфликт при удалении узла в цикле LIST( )LIST предусмотрен в слове NDEL
 DUP -ListNode @
 IF \ list \ переходим к следующему узлу списка
 DUP -ListNode @ @ SWAP -ListNode ! \ Устанавливаем следующий узел списка текущим
 ELSE \ list \ Список пуст; достигнут конец списка или цикл не инициализирован
 DUP ( -ListFirstNode ) @
 IF \ list \ Список не пуст, цикл не инициализирован.
 DUP ( -ListFirstNode ) @ SWAP \ Получаем первый узел списка
 -ListNode ! \ И устанавливаем его текущим узлом
 ELSE \ list \ Список пуст
 DROP \ Заголовок списка не нужен
 THEN
 THEN
 ;

 : LIST@ \ ( list -- nodevalue|0 ) \ Получить текущее значение пошагового цикла списка. При переходе через конец списка результатом будет ноль и только потом первый узел
 \ Именно такое решение обусловлено следующими моментами:
 \ - список может быть пустым - эта проверка нужна в любом случае;
 \ - упрощает слово LIST> ;
 \ - удобно использовать в цикле BEGIN WHILE REPEAT - ноль при достижении конца списка;
 \ - не нужно дополнительное слово для проверки достижения конца списка.
 DUP -ListNode @
 DUP IF
 SWAP NODE>@
 ELSE
 DROP -ListValCells @ 0 DO 0 LOOP
 THEN
 ;

 : LIST@> \ ( list -- nodevalue ) \ Получить текущее значение пошагового цикла и перейти к следующему узлу списка. Синоним фразы list LIST@ list LIST@>
 DUP >R LIST@ R> LIST>
 ;

 : LIST-- \ ( list -- ) \ Инициализировать пошаговый цикл списка list первым узлом.
 DUP @ SWAP -ListNode !
 ;

 \ *** Удаление узлов списка
 : NDEL \ ( -- ) \ Удалить текущий узел списка. Только внутри цикла LIST( )LIST
 ListSets @ \ node
 DUP @ SWAP \ node+1 node \ Получаем следующий узел списка и кладем его во вторую позицию в стеке
 List@ -ListNode @ OVER = \ И на всякий случай проверяем, не на текущем ли узле остановился пошаговый итератор:
 IF \ Да, удаляемый узел используется пошаговым итератором
 List@ LIST> \ Устанавливаем следующий узел как текущий для пошагового итератора
 THEN

 List@ -ListNodeFree @ EXECUTE THROW \ node+1 \ Освобождаем текущий узел
 DUP IF ELSE PNode@ List@ CELL+ ! THEN \ И если это последний в списке узел - то сохраняем его во вторую ячейку заголовка списка
 PNode@ ! \ Текущий узел записываем в предыдущий
 PNode@ ListSets ! \ И устанавливаем предыдущий узел текущим узлом для цикла FOR-LIST. Т.о. для цикла BEGIN слова FOR-LIST получается так, как если бы этот узел списка и не обрабатывался - как если бы прокрутили цикл на один шаг без изменения переменных.
 ;

 \ *** Удаление списка
 : LIST-FREE \ ( list -- ) \ Полностью очистить список.
 DUP -ListNode OFF \ Обнуляем текущий узел из заголовка
 DUP LIST( NDEL )LIST \ Удаляем все узлы списка
 DUP OFF \ Обнуляем первый узел из заголовка
 -ListLastNode OFF \ обнуляем последний узел из заголовка
 ;

 \ *** Удаление значения из списка
 : NODE-DEL \ ( value list --) Удалить первый узел, который содержит указанное значение
 DUP >R LIST( \ value
 VAL-DUP NODE@ VAL=
 IF
 NDEL
 LIST-EXIT
 THEN
 )LIST
 R> VAL-DROP>
 ;

 \ *** Поиск в списке
 : LIST? \ ( value list -- node|0) Проверить, хранится ли указанное значение в списке. Возвращает адрес узла, в котором хранится значение или 0, если значение не обнаружено.
 DUP >R
 0 SWAP LIST( \ value 0
 DROP
 VAL-DUP NODE@ VAL=
 IF
 LIST-EXIT NODE
 ELSE
 0
 THEN
 )LIST
 R> SWAP >R
 VAL-DROP>
 R>
 ;

 \ *** Добавление узлов в список
 : !LIST \ ( value list -- ) \ Добавить в начало списка значение value
 \ * Выделение памяти \ value list
 [ 2 CELLS LIT, ] OVER \ value list size list
 -ListAllocate @ EXECUTE THROW >R \ value list R: new-node
 \ * Пошаговый цикл \ value list R: new-node
 DUP ( -ListFirstNode ) @
 OVER -ListNode @ OVER 0= >R = R> OR
 IF \ Список пуст или пошаговый цикл был на первом узле списка?
 DUP -ListNode R@ SWAP ! \ Инициализируем пошаговый цикл создаваемым узлом
 THEN
 \ * Инициализация пустого списка \ value list R: new-node
 DUP ( -ListFirstNode ) @ \ Если первого узла в списке нет - значит список пустой
 IF ELSE R@ OVER -ListLastNode ! THEN \ Устанавливаем создаваемый узел как последний узел
 \ * Установка связи между новым и первым узлами
 DUP @ R@ ! \ value list R: new-node:node
 \ * Устанавливаем создаваемый узел в качестве первого узла списка
 R@ OVER ( -ListFirstNode ) ! \ value list R: new-node \ list:new-node
 \ * Запись значения \ value list R: new-node
 R> SWAP NODE>!
 ;

 : LIST! \ ( value list -- ) \ Добавить в конец списка значение value
 DUP -ListLastNode @ ?DUP
 IF \ В списке уже есть узлы
 \ * Выделение памяти \ value list lastnode
 OVER [ 2 CELLS LIT, ] SWAP \ value list lastnode size list R: new-node
 -ListAllocate @ EXECUTE THROW >R \ value list lastnode R: new-node
 \ * Установка связи между последним и новым узлами
 R@ SWAP ! \ value list R: new-node \ lastnode:new-node
 \ * Запись нового узла как последнего в заголовок списка
 R@ OVER -ListLastNode ! \ value list R: new-node \ list+cell:new-node
 \ * Запись значения
 R> SWAP NODE>!
 ELSE \ value list \ Это будет первый узел списка
 !LIST
 THEN
 ;

 \ *** Добавление нескольких значений
 : LIST#! \ ( val_1 ... val_n n list -- ) \ Добавить поочередно n значений со стека в конец списка list. Значения добавляются начиная с вершины стека в конец списка в порядке очереди.
 OVER IF
 SWAP 0 DO DUP >R LIST! R> LOOP DROP
 ELSE 2DROP THEN
 ;

 : #!LIST \ ( val_1 ... val_n n list -- ) \ Добавить поочередно n значений со стека в начало списка list. Значения добавляются начиная с вершины стека в начало списка в порядке очереди.
 OVER IF
 SWAP 0 DO DUP >R !LIST R> LOOP DROP
 ELSE 2DROP THEN
 ;

DEFINITIONS

 USER-VALUE list-pos
 USER-VALUE list-handle

EXPORT

 : LIST[ \ ( list -- list-handle list-pos ) \ Начать добавление значений в список.
 list-handle SWAP \ Сохраняем текущее значение list-handle на стеке
 TO list-handle \ И запоминаем список в list-handle
 list-pos \ Аналогично делаем и с list-pos
 DEPTH TO list-pos
 ;

 : ]LIST \ ( list-handle list-pos x*i -- ) \ Закончить добавление значений в список. Слово вычисляет число значений, оказавшихся на стеке после слова LIST[ и добавляет их все в начало списка по порядку.
 DEPTH list-pos -
 list-handle -ListValCells @ / \ Делим число элементов на стеке на размер элемента списка
 list-handle #!LIST \ Добавляем элементы в список
 TO list-pos \ Восстанавливаем list-pos и list-handle
 TO list-handle
 ;

 \ *** Подсчет числа узлов списка
 : LIST# \ ( list -- i ) \ Посчитать число узлов в списке list
 0 SWAP LIST( 1+ )LIST
 ;

 \ *** Получение узла по индексу
 : LIST#> \ ( i list -- node ) \ Получить узел node списка list под номером i
 0 SWAP LIST(
 2DUP =
 IF
 NODE LIST-EXIT
 ELSE
 1+
 THEN
 )LIST
 NIP NIP
 ;

 \ *** Получение значения по индексу
 : LIST#@ \ ( i list -- value ) \ Получить значение узла списка list
 SWAP OVER LIST#>
 SWAP NODE>@
 ;

EXPORT

 \ *** Создание именованного списка и генерация всех методов списка
 : (LIST) \ ( a_name u_name init_header -- )
 HERE >R /ListHeader ALLOT \ Выделяем память для заголовка
 R@ /ListHeader CMOVE>
 " VALUE %2OVER%" R> ROT ROT EVALUATE
 " : %2OVER%( POSTPONE %2OVER% [COMPILE] LIST( ; IMMEDIATE " EVALUATE
 " : )%2OVER% [COMPILE] )LIST ; IMMEDIATE " EVALUATE
 " : %2OVER%> %2OVER% LIST> ; " EVALUATE
 " : %2OVER%@ %2OVER% LIST@ ; " EVALUATE
 " : %2OVER%@> %2OVER% LIST@> ; " EVALUATE
 " : %2OVER%-- %2OVER% LIST-- ; " EVALUATE
 " : %2OVER%? %2OVER% LIST? ; " EVALUATE
 " : !%2OVER% %2OVER% !LIST ; " EVALUATE
 " : %2OVER%! %2OVER% LIST! ; " EVALUATE
 " : %2OVER%#! %2OVER% LIST#! ; " EVALUATE
 " : #!%2OVER% %2OVER% #!LIST ; " EVALUATE
 " : %2OVER%[ %2OVER% LIST[ ; " EVALUATE
 " : ]%2OVER% ]LIST ; " EVALUATE
 " : %2OVER%# %2OVER% LIST# ; " EVALUATE
 " : %2OVER%#> %2OVER% LIST#> ; " EVALUATE
 " : %2OVER%#@ %2SWAP% LIST#@ ; " EVALUATE
 ;


 \ *** Именованные статические списки
 : LIST: \ ( " name" -> ) \ Создать список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Слово является VALUE-переменной. В задачах добавлять и читать значения из списка следует в разделе Action:, не раньше.
 BL PARSE ListHeader (LIST)
 ;

 : GLOBAL-LIST: \ ( " name" -> ) \ Создать глобальный список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Список доступен для всех потоков. Слово является VALUE-переменной. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.
 BL PARSE GlobalListHeader (LIST)
 ;

DEFINITIONS

 \ *** Расширения списков
 \ * Запись строки
 : NodeS! \ ( a u node list -- )
 OVER CELL+ @ DUP \ Освобождаем старую строку, если она есть
 IF
 OVER -ListFree @ EXECUTE THROW
 ELSE DROP THEN

 -ListAllocate @ SWAP >R >R \ Выделяем память для новой строки и записываем её в узел списка
 DUP [ CELL 1+ LIT, ] + \ a u u+cell+1
 R> EXECUTE THROW >R \ a u R: a0
 DUP R@ ! \ a u R: a0
 R@ CELL+ SWAP \ a a1 u
 CMOVE
 R> R> CELL+ !
 ;

 \ * Извлечение строки
 : NodeS@ \ ( node -- a u )
 CELL+ @ DUP @ SWAP CELL+ SWAP
 ;

 \ * Сравнение строк
 : s= \ ( a1 u1 a2 u2 -- ? )
 COMPARE 0=
 ;

 : NodeFree \ ( node -- ior )
 DUP CELL+ @ FREE THROW
 FREE
 ;

 : GlobalNodeFree \ ( node -- ior )
 DUP CELL+ @ GLOBAL-FREE THROW
 GLOBAL-FREE
 ;


 CREATE GlobalStringListHeader 0 , 0 , 0 , 2 ,
 ' GLOBAL-ALLOCATE ,
 ' GLOBAL-FREE ,
 ' GlobalNodeFree ,
 ' NodeS@ ,
 ' NodeS! ,
 ' s= ,
 ' 2DROP ,
 ' 2DUP ,

 CREATE StringListHeader 0 , 0 , 0 , 2 ,
 ' ALLOCATE ,
 ' FREE ,
 ' NodeFree ,
 ' NodeS@ ,
 ' NodeS! ,
 ' s= ,
 ' 2DROP ,
 ' 2DUP ,

EXPORT

 : STRING-LIST: \ ( " name" -> ) \ Создать строковый список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Слово является VALUE-переменной. В задачах добавлять и читать значения из списка следует в разделе Action:, не раньше.
 BL PARSE StringListHeader (LIST)
 ;

 : GLOBAL-STRING-LIST: \ ( " name" -> ) \ Создать глобальный строковый список, имя списка берется из входного потока. Для заголовка списка выделяется память из кодофайла: список можно освободить, но нельзя уничтожить. Список доступен для всех потоков. Слово является VALUE-переменной. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.
 BL PARSE GlobalStringListHeader (LIST)
 ;

 \ *** Автоматическое создание и уничтожение списков
 : LIST \ ( -- list ) \ Создать список. Для заголовка списка выделяется память из хипа: такой список можно уничтожить.
 /ListHeader ALLOCATE THROW
 ListHeader OVER /ListHeader CMOVE
 ;

 : GLOBAL-LIST \ ( -- list ) \ Создать глобальный список. Для заголовка списка выделяется память из глобального хипа: такой список можно уничтожить. Список доступен для всех потоков. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.
 /ListHeader GLOBAL-ALLOCATE THROW
 GlobalListHeader OVER /ListHeader CMOVE
 ;

 : STRING-LIST \ ( -- list ) \ Создать строковый список. Для заголовка списка выделяется память из хипа: такой список можно уничтожить. Работает исколючительно со строками. Динамически выделяет и освобождает для строк память.
 /ListHeader ALLOCATE THROW
 StringListHeader OVER /ListHeader CMOVE
 ;

 : GLOBAL-STRING-LIST \ ( -- list ) \ Создать глобальный строковый список. Для заголовка списка выделяется память из глобального хипа: такой список можно уничтожить. Список доступен для всех потоков. Работает исколючительно со строками. Динамически выделяет и освобождает для строк память. Добавлять и читать значения из глобального списка можно сразу же после его создания и из любого потока и любой задачи.
 /ListHeader GLOBAL-ALLOCATE THROW
 GlobalStringListHeader OVER /ListHeader CMOVE
 ;

 : LIST-DEL \ ( list -- ) \ Уничтожить список и все его содержимое.
 DUP LIST-FREE
 DUP -ListFree @ EXECUTE THROW
 ;

;MODULE
User avatar
Morituruz
 
Posts: 727
Joined: Sun, 14 Oct 2007, 01:51

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby VoidVolker » Tue, 25 Sep 2012, 18:26

Moriturus wrote:Я проверил на почти чистом nncron, работает.
У вас плагин lists самый свежий? Со свежим у меня что-то совсем ничего не работало, я на предыдущей версии сижу, VoidVolker сказал локализовывать, да всё времени нет.

А вот об этом факте стоило бы сообщить мне сразу. В новой версии как раз изменился алгоритм работы со строками. В сообщении SeMa хорошо видно, что ошибка возникает при попытке извлечения строки из узла списка. Это может быть связано с получением некорректного адреса узла.

Потестировал задачку: нашел баг при удалении узла списка. С новым плагином должно работать как надо.
P. S. Код не самый оптимальный, есть куда стремиться.
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby SeMa » Fri, 28 Sep 2012, 17:44

VoidVolker
Спасибо. Вроде бы работает.

VoidVolker, Moriturus
Но есть ещё некоторые (пока две) непонятки. Нет времени изучить досконально.

1. (это к Moriturus точно) если в каталоге с уже "почищеными" файлами запустить задачу повторно (а удалять нечего!), то после отработки остаётся зелёный хинт.
2. (будет время -- посмотрю внимательней) файлов-"оригиналов" почему-то стало меньше.
Компьютер ─ устройство, разработанное для ускорения и автоматизации человеческих ошибок
User avatar
SeMa
 
Posts: 637
Joined: Fri, 15 Apr 2005, 12:49
Location: Украина

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby VoidVolker » Fri, 28 Sep 2012, 17:49

Кстати да, у меня тоже один раз она почистила все файлы в тестовом каталоге. Так что я думаю, что она все еще сыровата. И не выводит список дубликатов, и оставляет не самые удачные имена.
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby Morituruz » Mon, 01 Oct 2012, 14:44

SeMa wrote:1. (это к Moriturus точно) если в каталоге с уже "почищеными" файлами запустить задачу повторно (а удалять нечего!), то после отработки остаётся зелёный хинт.

Это связано с тем, что у вас в каталоге осталось мало файлов, и поиск проходит слишком быстро, хинтовые слова не успевают отработать.

SeMa wrote:2. (будет время -- посмотрю внимательней) файлов-"оригиналов" почему-то стало меньше.

Не сталкивался.

VoidVolker wrote:Кстати да, у меня тоже один раз она почистила все файлы в тестовом каталоге.

Вы наверное испытвали на нестабильной бете плагина lists :)

VoidVolker wrote:И не выводит список дубликатов

Как это не выводит, там же экспорт в текстовый файл, который потом открывается если надо. Группы одинаковых файлов отделены двойным переносом строки, и первый в группе — «оригинал».
VoidVolker wrote:оставляет не самые удачные имена

Я выше уже писал, логика простая — кто первый в файловой системе нашёлся, тот и считается оригиналом, а что значит удачное или неудачное имя я не знаю :)
User avatar
Morituruz
 
Posts: 727
Joined: Sun, 14 Oct 2007, 01:51

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby VoidVolker » Mon, 01 Oct 2012, 18:22

Moriturus wrote:
VoidVolker wrote:И не выводит список дубликатов

Как это не выводит, там же экспорт в текстовый файл, который потом открывается если надо. Группы одинаковых файлов отделены двойным переносом строки, и первый в группе — «оригинал».

А, точно, должен блокнот открываться. Не обратил внимания при тестировании. Я подумал в консоли будет список выведен - удобнее же. Там же можно выбрать и файлы для удаления.
Кстати, файл создавать не обязательно: можно просто в буфер обмена записать строку и открыв блокнот хоткеем вставить.
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby Morituruz » Mon, 01 Oct 2012, 19:00

VoidVolker wrote:Я подумал в консоли будет список выведен - удобнее же.

Когда файлов штук 100 — удобнее наверное, но 100 файлов я и в тотале найду и удалю :)
В блокнот же влезет куча файлов. Из него список можно и в тотал скопировать в выделение.
VoidVolker wrote:файл создавать не обязательно: можно просто в буфер обмена записать строку и открыв блокнот хоткеем вставить.

Тогда в задаче нужно будет прописывать путь до вашего любимого блокнота, потому, что мой любимый блокнот (AkelPad) не обязательно такой же как у вас, а открывая файл, мы открываем в ассоциированном приложении. Всё уже продумано :)
VoidVolker wrote:Там же можно выбрать и файлы для удаления.

:shock: а как в консоли можно что-либо выбрать?
User avatar
Morituruz
 
Posts: 727
Joined: Sun, 14 Oct 2007, 01:51

Re: Удаление одинаковых файлов (по MD5/размеру)

Postby VoidVolker » Mon, 01 Oct 2012, 20:15

Moriturus wrote:мой любимый блокнот (AkelPad) не обязательно такой же как у вас

Такой же. А для кода SciTE.
Moriturus wrote::shock: а как в консоли можно что-либо выбрать?

Code: Select all
KEY
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Next

Return to nnCron forum (Russian)

Who is online

Users browsing this forum: Yahoo [Bot] and 3 guests

cron