Как прочитать файл .txt в обратном порядке с помощью пакетной службы

У меня есть файл data.txt, который я анализирую в своем скрипте .cmd, я просматриваю его от первой строки до последней. Я хочу начать с последней строки и вместо этого перейти к первой.

FOR /F "EOL=; TOKENS=1 DELIMS = " %%r IN (datafile) DO (CALL :DeleteFolder %%r)

Как я смогу изменить порядок чтения?

Я пытался найти синтаксис для «FOR /....», но, похоже, невозможно найти хорошую документацию для .cmd или пакетных файлов (вопрос в вопросе: файл .cmd совпадает с пакетным файлом и .bat, синтаксис кажется таким же, и всякий раз, когда я ищу файл .cmd, мне отображается справка по пакетному файлу).

Это образец файла данных, с которым я сейчас работаю в целях тестирования. Реальный файл данных будет состоять из пары сотен строк и часто меняться, он должен составлять около 300 строк. По сути, это определение структуры папок и подпапок.

; This is a comment line
DEV1
DEV2
DEV3
DEV4
DEV5
DEV6
DEV7
DEV8
DEV9
DEV10
; This is a comment line
is a .cmd file the same as a batch file and a .bat file - есть небольшие отличия, но по сути да.
Magoo 09.07.2024 21:00

Пожалуйста, внесите в свой вопрос репрезентативный образец вашего файла данных. Поможет ли обратная сортировка?

Magoo 09.07.2024 21:02

Вы не можете «обратить порядок чтения»! Файл все равно будет прочитан с самого начала. У вас будет возможность прочитать все строки с начала файла и сохранить каждую строку в обратном порядке. Как вы можете себе представить, во всех файлах, кроме небольших, для этого потребуется либо большой буфер памяти, либо временный файл. Также в вашем примере EOL=; TOKENS=1 не требуется, а CALL :DeleteFolder %%r должно быть CALL :DeleteFolder "%%~r".

Compo 09.07.2024 21:40

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

denseTurtle 10.07.2024 13:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Короткий ответ: вы не можете. Файл всегда читается в естественном порядке. Обычный способ решения этой проблемы — сохранить все строки файла в переменных и затем обработать переменные в обратном порядке. Проблемы с этим методом возникают, когда файл большой, поскольку пространство для переменных ограничено, и процесс становится медленнее по мере увеличения размера файла...

Я разработал интересный метод обработки строк файла в обратном порядке, не использующий переменные. Вместо этого он сохраняет каждую ожидающую строку в заменяемом параметре FOR и обрабатывает несколько строк посредством вложенных рекурсивных вызовов подпрограммы, содержащей команду FOR. Таким образом, максимальное количество строк, которые можно обработать с помощью этого метода, — это максимальный уровень вызовов подпрограмм, которые поддерживает cmd.exe, который, я думаю, составляет несколько сотен.

В любом случае, этот метод интересен! ;)

@echo off
setlocal EnableDelayedExpansion

set "last=1"
:rolling
set "first=0"
for /F "delims = " %%a in (data.txt) do if defined last (
   set /A first+=1
   if !first! equ %last% (
      set /A last+=1
      call :rolling
      echo(%%a
      set "last = "
   )
)
exit /B

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

@echo off
setlocal EnableDelayedExpansion

rem/> output.txt
for /F "delims = " %%a in (test.txt) do (
   (
   echo(%%a
   type output.txt
   ) > temp.txt
   move /Y temp.txt output.txt > NUL
)

Спасибо за помощь, сейчас пытаюсь реализовать. У меня возникли проблемы с пониманием того, где я буду вызывать функцию DeleteFolder. Я новичок в пакетном написании сценариев, почему вы используете ! чтобы заключить первую переменную, а не %%, как обычно заключаются переменные, и является ли последняя проверка «делать, если определено» истинной/ложной?

denseTurtle 10.07.2024 14:11

@NimaPishva второй пример должен быть довольно очевиден. Файл output.txt представляет собой перевернутый файл. Итак, теперь вы просто используете это с существующей командой for. FOR /F "EOL=; TOKENS=1 DELIMS = " %%r IN (output.txt) DO (CALL :DeleteFolder %%r)

Squashman 10.07.2024 18:14

спасибо, мне удалось заставить его работать.

denseTurtle 10.07.2024 20:54

Что ж, этот метод должен работать быстрее, чем другой, который выполняет команду findstr в каждой строке файла...

Aacini 10.07.2024 23:33

Предел рекурсии составляет 339. Это пугающе близко к «паре сотен… около 300». Подготовьтесь к переполнению стека (каламбур), если вы используете этот (рекурсивный) метод. Хотя интересное решение. Второе предложение выполняет как минимум две операции записи на строку (должно быть «медленно» на вращающихся дисках).

Stephan 11.07.2024 09:42
Ответ принят как подходящий
  • создать временный файл с номерами строк (при необходимости удалив строки комментариев)
  • Подсчитайте количество строк для обработки
  • Используйте цикл for /L для обработки их в обратном порядке.
  • удалить временный файл (необязательно)
    @echo off
    setlocal
    
    set "file=data.txt"
    REM create a file with line numbers (while removing comments):
    findstr /bv ";" "%file%" | findstr /n "^" > "%file%.tmp"
    
    REM find number of lines:
    for /f %%i in ('type "%file%.tmp"^|find /c /v ""') do set lines=%%i
    
    REM process them in reverse order:
    for /l %%i in (%lines%,-1,1) do (
      for /f "tokens=1,* delims=:" %%x in ('findstr /b "%%i:" "%file%.tmp"') do (
        echo processing line number %%x:        %%y
      )
    )
    del "%file%.tmp"

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

Пустые строки сохраняются (в примере данных их нет), но при необходимости их можно отфильтровать с помощью другого findstr.

Спасибо, это сработало, мой файл данных перевернут! в консоли. Однако когда я вставляю вызов: DeleteFolder, он не работает. Например, куда пойдет мой вызов функции?

denseTurtle 10.07.2024 16:59

У меня получилось, спасибо!

denseTurtle 10.07.2024 17:08

Другие вопросы по теме