Перенаправленный стандартный ввод заканчивается преждевременно Lua для Windows

Я использую Lua в окне cmd под Windows. Я использую «кошку» (из UnxUtils), чтобы передать файл Lua-скрипту. Сценарий использует "io.read(1)" для чтения по одному байту за раз.

local b, n ;
n = -1 ;
b = true ;
while b do
  n = n + 1 ;
  b = io.read(1) ;
end ;
print( n, "bytes read" ) ;

Когда я передаю скрипту файл .EXE размером 333 КБ, он заявляет, что «прочитано 24025 байт». Подайте тот же .EXE на «wc» (другой UnxUtils), и wc правильно скажет 333008.

> cat "Firefox Installer.exe" | lua count.lua
24025   bytes read
cat: write error: Invalid argument
> cat "Firefox Installer.exe" | wc
   1408    8674  333008

Поскольку я получаю ожидаемый ответ, когда я "cat | wc", я не думаю, что что-то не так с программой "cat" или с реализацией перенаправления Windows.

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

Я просмотрел входной файл, чтобы увидеть, были ли Ctrl-Z или Ctrl-D причиной раннего отключения - они появляются в файле очень рано.

Я попытался прочитать после того, как «io.read()» вернул «false»: скрипт признал, что видит больше байтов, но все же не более 45 КБ из 333 КБ входного файла.

Вероятно, это проблема Windows (см., например, этот ответ ). Windows по-разному обрабатывает двоичные и текстовые «потоки»/файлы. Я бы предположил, что стандартный ввод ваших программ по умолчанию является текстовым потоком; позже невозможно изменить режим stdin на двоичный, используя простой Lua, для этого вам понадобится библиотека. Что-то вроде lfs = require("lfs"); lfs.setmode(io.stdin, "binary") может работать (используя библиотеку LuaFileSystem). Вы также можете попытаться исправить вызов скрипта, чтобы установить правильный режим.

LMD 31.01.2023 22:21

@LMD Кажется, это моя проблема. Программа Visual Studio C++, выполняющая "fread(&c,1,1,stdin)", также останавливается. Добавление "_setmode(_fileno(stdin),_O_BINARY)" приводит к тому, что программа считывает правильное количество байтов. Я не понимаю, почему каждая программа видит столько, сколько видит - Lua читает 24025 байт, C читает 1169 - но это почти наверняка проблема.Отправьте ответ, и я выберу его.

Jay Michael 01.02.2023 04:30

В списке рассылки был пост, но запрошенное изменение не было реализовано, поскольку оно не переносимо (зависит от ОС и компилятора: решение отличается для MinGW и VisualStudio).

ESkri 01.02.2023 05:57

@LMD - You could also try to fix your script invocation to set the correct mode - Как можно повторно открыть стандартный ввод как двоичный извне программы?

ESkri 01.02.2023 05:59

@ESkri, как вы можете сказать, я не использую Windows и не пробовал;) но я полагаю, что должна быть программа, которая устанавливает stdin в двоичный режим, а затем вызывает сценарий Lua вот так. Таким образом, вы можете оставить Lua нетронутым. Затем вам нужно будет изменить вызов на cat "Firefox Installer.exe" | ./stdbin lua count.lua.

LMD 01.02.2023 08:10
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Скопировано из моих комментариев:

Вероятно, это проблема Windows (см., например, этот ответ ). Windows по-разному обрабатывает двоичные и текстовые «потоки»/файлы. Я бы предположил, что стандартный ввод вашей программы по умолчанию является текстовым потоком; позже невозможно изменить режим стандартного ввода на двоичный, используя простой Lua, для этого вам понадобится библиотека. Что-то вроде lfs = require("lfs"); lfs.setmode(io.stdin, "binary") может работать (используя библиотеку LuaFileSystem).

Вы также можете попытаться исправить вызов скрипта, чтобы установить правильный режим, используя скрипт, который изменяет stdin на двоичный режим перед вызовом скрипта Lua:

./stdbin.c:

#include <stdio.h>
#include <unistd.h>
#include <assert.h>

int main(int argc, char** argv) {
    if (argc < 1) {
        printf("Arguments: <program> {args}\n");
        return 1;
    }

    // See  https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?redirectedfrom=MSDN&view=msvc-170
    if (_setmode(_fileno(stdin), _O_BINARY) == -1)
        perror("_setmode failed");

    execvp("lua", ++argv);
    // execvp only returns if there is an error
    perror("execvp failed");
    return 1;
}

Примечание: не проверено. Использование: ./stdbin lua count.lua.

Ух ты! Windows представила execvp, которого не было 10 лет назад.

ESkri 01.02.2023 08:32

Хм, мне, вероятно, следует использовать _execvp вместо этого (learn.microsoft.com/en-us/cpp/c-runtime-library/reference/… ‌​).

LMD 01.02.2023 10:01

(Это дополнение к ответу LMD)
В LuaJIT не нужны внешние библиотеки и исполняемые файлы:

local ffi = require"ffi"
ffi.cdef"int _setmode(int,int)"
ffi.C._setmode(0, 0x8000)
-- Now io.read() will return binary data

Полагаться на _O_BINARY, чтобы быть 0x8000, нормально?

LMD 01.02.2023 10:02

LuaJIT не имеет доступа к реальным файлам Windows SDK, чтобы определить значение этой константы в текущей версии Windows, поэтому единственный способ — полагаться на константу, известную на момент написания кода :-)

ESkri 01.02.2023 10:35

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