как я могу использовать для / F, чтобы сделать паузу в «текущей» строке - PullRequest
0 голосов
/ 27 февраля 2019

Можно ли использовать команду for /f в CMD для постепенного чтения файла?Я хотел бы иметь возможность изменять строки в файле, которые «не были прочитаны» (т. Е. Еще не были обработаны в цикле), но, похоже, это не дает никакого эффекта.

Например, скажем, мой файл temp.txt состоит из трех строк:

one
# two
# three

, и я использую

for /f "eol=#" %i in (temp.txt) do @echo %i & sleep 10s

Когда я выполню это, а затем в течение первых десяти секунд удалите хеш-метки исохранить файл, я не получаю все три строки (как я ожидаю / ищу).Я ожидаю, что, поскольку я удалил хеш-метки (в течение первых 10 секунд), которые к тому времени, когда цикл попадает на вторую строку, он не будет пропущен, потому что хеш-метка отсутствует.Кажется, что весь файл читается первым, прежде чем обрабатывается даже первая строка (или, может быть, какой-то его «большой» блок?).Есть ли способ заставить цикл читать каждую строку только тогда, когда он «используется» (т. Е. Не читать вперед и просто ждать, пока он не будет готов к следующей)?

1 Ответ

0 голосов
/ 27 февраля 2019

Цикл for /F , кажется, читает весь текстовый файл одновременно 1 .Чтобы увидеть какие-либо изменения в данном файле, его нужно открывать и закрывать для чтения каждой отдельной строки.В любом случае, вы также должны учитывать, что строки могут быть вставлены или удалены, поэтому вывод может быть не таким, как вы ожидаете.

Следующий код должен делать то, что вы хотите - см. Все пояснительные замечания rem:

@echo off
rem // Define file path/name here:
set "FILE=%~dpn0.txt"
rem // Determine number of lines - 1:
for /F %%C in ('^< "%FILE%" find /C /V ""') do set /A "CNT=%%C-1"
rem // Iterate through all 0-based line numbers:
for /L %%I in (0,1,%CNT%) do (
    rem // Wait for some time:
    > nul timeout /T 3 /NOBREAK
    rem // Read a single line in a sub-routine:
    call :SUB "%FILE%" %%I
)
exit /B


:SUB
    rem // Prepare `skip` option for `for /F` loop (to skip current line number - 1):
    if %~2 equ 0 (set "SKIP=") else (set "SKIP=skip=%~2")
    rem /* Read single line; `findstr` prefixes them with a line number to preserve
    rem    empty lines (remember that `for /F` skips them otherwise, so letting them
    rem    alone would lead to `for /F` returning the next non-empty line): */
    for /F "%SKIP% delims=" %%L in ('findstr /N "^" "%~1"') do (
        rem // Store the read line, including the line number prefix:
        set "LINE=%%L"
        rem // Exit the loop, hence skip the rest of the file:
        goto :END
    )
:END
    rem /* Return the read line with the line number prefix removed;
    rem    delayed expansion avoids trouble with special characters: */
    setlocal EnableDelayedExpansion
    (
        for /F "delims= eol=#" %%K in ("!LINE:*:=!") do endlocal & echo(%%K
    ) || endlocal
    exit /B

Этот скрипт придерживается определенных номеров строк, поэтому:

  • при вставке строк:
    • столько строк в конце отсутствует навыводим как вы вставили;
    • столько строк возвращено дважды, сколько вы вставили перед текущей обработанной строкой;
  • при удалении строк:
    • к концу добавлено столько пустых строк, сколько вы удалили;
    • пропущено столько строк, сколько вы удалили до текущей обработанной строки;

1) Я экспериментировал с файлом, содержащим 64 КБ строки по 8 КБ каждая, изменяя последнюю строку, позволяя for /F прочитать файл, и это изменение не было отражено в выходных данных;хотя для такого поведения может быть ограничение по размеру, но я пока не могу это выяснить;также приложение для изменения текстового файла играет здесь свою роль, поскольку оно может фактически работать с временной копией, а не с данным файлом, поэтому могут быть сделаны неправильные выводы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...