Существует два относительно простых способа сортировки файлов в обратном порядке.Первый - это прямой метод над содержимым файла: добавьте номера строк во все строки, отсортируйте файл в обратном порядке, исключите номера строк:
@echo off
setlocal EnableDelayedExpansion
rem Insert line numbers in all lines
for /F "tokens=1* delims=:" %%a in ('findstr /n ^^ %1') do (
set /A lineNo=1000000+%%a
echo !lineNo!:%%b>> tempfile.txt
)
rem Sort the file and show the result
for /F "tokens=1* delims=:" %%a in ('sort /r tempfile.txt') do (
echo Line %%a is %%b
)
Другой метод заключается в загрузке строк файла в пакете.массив, который может быть обработан любым способом:
@echo off
setlocal EnableDelayedExpansion
rem Load file lines in a Batch array
set lineNo=0
for /F "delims=" %%a in (%1) do (
set /A lineNo+=1
set "line[!lineNo!]=%%a"
)
rem Process array elements in reversed order:
for /L %%i in (%lineNo%,-1,1) do (
echo Line %%i is !line[%%i]!
)
Этот последний метод работает, только если размер файла меньше 64 МБ, потому что это ограничение для пакетных переменных.
Оба метода могут быть изменены для правильной обработки специальных символов (> <|). </p>
HOWEVER
Если вы хотите удалить все содержимое дерева папки в порядке снизу вверх, «правильный» способ сделать это с помощью рекурсивной подпрограммы ...
РЕДАКТИРОВАТЬ Ответ на dbenham
Как я уже писал в своем ответе, два предложенных мною метода могут быть изменены для правильной обработки специальных символов и пустых строк.В своем ответе я показал общий метод для «изменения порядка строк» в обратном порядке, не обращая особого внимания на создание выходного файла , потому что ОП сказал в своем собственном ответе, что «Цель состояла в том, чтобы переупорядочить список папок, чтобы избежать проблем при их последовательном удалении », поэтому я подумал, что этого достаточно, чтобы показать ему, как обрабатывать папок в обратном порядке.Я также предположил, что список папок:
- Не иметь восклицательных знаков (!).
- Не иметь начальных двоеточий (:).
- Имена папок корочечем 4096 байт.
- Иметь менее 1000000 строк.
- Не иметь пустых строк.
Я даже думал (и до сих пор думаю), что метод нужен ОПиспользовать для удаления списка папок недостаточно, и я упомянул об этом под большим HOWEVER в своем ответе, предлагающем вместо этого использовать рекурсивную подпрограмму.
Однако кажется, что dbenham подумал, что первоначальный вопрос был чем-то похожим на «Какой самый эффективный метод сортировки большого файла в обратном порядке?»и критиковать мои методы, потому что у них нет таких функций.По этой причине я должен ответить в терминах этого нового вопроса (эффективный метод), верно?
Во-первых, мне смешно, что dbenham критикует мои методы, потому что "на самом деле не предоставляет запрашиваемое решение(фактический вывод файла) ", но в своем собственном Модифицированном решении 2 он написал, что" Это мое любимое решение, потому что вывод файла, вероятно, может быть исключен путем непосредственной обработки файла в переменных, что полностью исключает создание любого временного файла.».???
Два метода, предложенных dbenham, имеют серьезную проблему с точки зрения эффективности, которая уже обсуждалась в этом вопросе : выполняется пара команд setlocal EnableDelayedExpansion
и endlocal
с каждой строкой файла .Если файл большой (т.е. 200 000 строк и около 8 МБ, как в предыдущем вопросе), среда будет скопирована в новую область памяти, а затем удалена, и это будет повторяться 200 000 раз!Конечно, эта задача отнимает много времени.Эта проблема усугубляется в Модифицированном решении 2 компании dbenham: по мере обработки строк среда растет, так как в этот момент хранится содержимое файла.В последних строках файла среда, почти равная размеру всего файла, будет скопирована в новую область памяти для каждой оставшейся строки файла .Конечно, это наихудший способ достижения этого процесса с точки зрения эффективности!
Существует еще один способ обработки пустых строк и специальных символов, для которых не требуется пара setlocal EnableDelayedExpansion - endlocal
.Подробнее об этом методе и дальнейшем обсуждении эффективных способов обработки больших файлов см. Ранее упомянутый вопрос.
Следующие пакетные файлы являются моими модифицированными версиями в разделе «Как отсортировать большой файл в обратном порядке в эффективномпуть».
Модифицированное решение 1: использование временного файла с SORT
@echo off
setlocal EnableDelayedExpansion
set revfile="%~1.rev"
set tempfile=%temp%\revfile%random%
rem Insert line numbers in all lines
findstr /n ^^ %1 > "%tempfile%1.txt"
find /c ":" < "%tempfile%1.txt" > "%tempfile%2.txt"
set /P lines=< "%tempfile%2.txt"
call :JustifyLineNumbers < "%tempfile%1.txt" > "%tempfile%2.txt"
del "%tempfile%1.txt"
rem Sort the file in reversed order
sort /rec 8192 /r "%tempfile%2.txt" /o "%tempfile%3.txt"
del "%tempfile%2.txt"
rem Remove line numbers
call :RemoveLineNumbers < "%tempfile%3.txt" > %revfile%
del "%tempfile%3.txt"
goto :EOF
:JustifyLineNumbers
for /L %%i in (1,1,%lines%) do (
set /A lineNo=1000000000+%%i
set /P line=
echo !lineNo!!line:*:=!
)
exit /B
:RemoveLineNumbers
for /L %%i in (1,1,%lines%) do (
set /P line=
echo !line:~10!
)
exit /B
Это решение по-прежнему имеет ограничение «только» 1147483647 строк (максимальное 32-разрядное положительное целое число со знаком минус минусначальное семя).Хотя этот предел может быть легко увеличен способом, предложенным dbenham, эта модификация подразумевает более медленную скорость выполнения.Вывод таков: если вы действительно хотите выполнить обратную сортировку очень большого файла, не используйте пакетный файл, но используйте более эффективный язык программирования (например, C).
Модифицированное решение 2: с использованием массива пакетных переменных
@echo off
setlocal EnableDelayedExpansion
set revfile="%~1.rev"
set tempfile=%temp%\revfile%random%
rem Load file lines in a Batch array
findstr /n ^^ %1 > "%tempfile%1.txt"
find /c ":" < "%tempfile%1.txt" > "%tempfile%2.txt"
set /P lines=< "%tempfile%2.txt"
del "%tempfile%2.txt"
call :CreateArray < "%tempfile%1.txt"
del "%tempfile%1.txt"
rem Process array elements in reversed order:
(for /L %%i in (%lines%,-1,1) do echo=!ln%%i!) > %revfile%
goto :EOF
:CreateArray
for /L %%i in (1,1,%lines%) do (
set /P line=
set ln%%i=!line:*:=!
)
exit /B
РЕДАКТИРОВАТЬ A возможно решение для большой проблемы среды.
Я разработал идею, которая может решить, по крайней мере частично, проблемы с производительностью команды SET, вызванные очень большой средой.Предположим, что внутренняя операция команды SET VAR=VALUE
выполняется следующим образом:
- Когда определяется новая переменная со значением, превышающим текущий размер среды, среда копируется в новую область, еслиобласть за ее пределами недоступна.
- Новая область достаточно велика, чтобы получить новую переменную.Дополнительное пространство не зарезервировано.
- Важное значение : при удалении большой переменной оставшееся свободное пространство NOT освобождается.Блок памяти среды никогда не сокращается.
Если предыдущие шаги верны, то проблемы с производительностью могут уменьшиться, если мы сначала зарезервируем желаемое пространство среды через большие (8 КБ) переменные с тем же именемрабочие переменные.Например, чтобы зарезервировать 1024 КБ, мы определяем 128 больших переменных;Я полагаю, что время, необходимое для определения этих 128 переменных, будет меньше, чем время, необходимое для заполнения тех же 1024 КБ более короткими переменными.
Когда процесс запущен, определение первых 128 рабочих переменных займетВремя, необходимое для удаления переменной 8 КБ и определения более короткой, но для переменной 129 процесс должен быть быстрее, поскольку он просто определяет новую переменную в уже доступном пространстве.Чтобы помочь этому процессу, переменные должны иметь имена, которые помещают их в конец среды, как указано в dbenham.
:ReserveEnvSpace sizeInKB
rem Define the first large variable (reserving 6 bytes for variable name)
rem (this method may be done in larger chunks until achieve the fastest one)
set z1=X
for /L %%i in (1,1,8184) do set z1=!z1!X
rem Define the rest of large variables
set /A lastVar=%1 / 8
for /L %%i in (2,1,%lastVar%) do set z%%i=!z1!
exit /B
Вы можете использовать команду MEM /P
, чтобы проверить размер и расположение памяти средыблок.В старые времена MS-DOS (command.com) среда размещалась после command.com, но если резидентная программа размещалась после среды, она больше не может расти.По этой причине в command.com был предоставлен ключ / E: nnnnn, чтобы зарезервировать определенный размер в байтах для среды.
У меня нет времени проверять этот метод до конца дня, но здесьэто для вас!