Я использую 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 КБ входного файла.
@LMD Кажется, это моя проблема. Программа Visual Studio C++, выполняющая "fread(&c,1,1,stdin)", также останавливается. Добавление "_setmode(_fileno(stdin),_O_BINARY)" приводит к тому, что программа считывает правильное количество байтов. Я не понимаю, почему каждая программа видит столько, сколько видит - Lua читает 24025 байт, C читает 1169 - но это почти наверняка проблема.Отправьте ответ, и я выберу его.
В списке рассылки был пост, но запрошенное изменение не было реализовано, поскольку оно не переносимо (зависит от ОС и компилятора: решение отличается для MinGW и VisualStudio).
@LMD - You could also try to fix your script invocation to set the correct mode
- Как можно повторно открыть стандартный ввод как двоичный извне программы?
@ESkri, как вы можете сказать, я не использую Windows и не пробовал;) но я полагаю, что должна быть программа, которая устанавливает stdin
в двоичный режим, а затем вызывает сценарий Lua вот так. Таким образом, вы можете оставить Lua нетронутым. Затем вам нужно будет изменить вызов на cat "Firefox Installer.exe" | ./stdbin lua count.lua
.
Скопировано из моих комментариев:
Вероятно, это проблема 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 лет назад.
Хм, мне, вероятно, следует использовать _execvp
вместо этого (learn.microsoft.com/en-us/cpp/c-runtime-library/reference/… ).
(Это дополнение к ответу 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
, нормально?
LuaJIT не имеет доступа к реальным файлам Windows SDK, чтобы определить значение этой константы в текущей версии Windows, поэтому единственный способ — полагаться на константу, известную на момент написания кода :-)
Вероятно, это проблема Windows (см., например, этот ответ ). Windows по-разному обрабатывает двоичные и текстовые «потоки»/файлы. Я бы предположил, что стандартный ввод ваших программ по умолчанию является текстовым потоком; позже невозможно изменить режим
stdin
на двоичный, используя простой Lua, для этого вам понадобится библиотека. Что-то вродеlfs = require("lfs"); lfs.setmode(io.stdin, "binary")
может работать (используя библиотеку LuaFileSystem). Вы также можете попытаться исправить вызов скрипта, чтобы установить правильный режим.