如何在 EOF 后再次从标准输入读取?
How do I read from standard input again after an EOF?
我有以下 C 程序:
#include <stdio.h>
#include <unistd.h>
void readAndEchoAll(void) {
for(;;) {
char buf[100];
ssize_t size = read(STDIN_FILENO, buf, sizeof(buf));
if(size <= 0) {
return;
}
fwrite(buf, 1, size, stdout);
}
}
int main(void) {
puts("Reading and echoing STDIN until first EOF...");
readAndEchoAll();
puts("Got first EOF. Now reading and echoing STDIN until second EOF...");
readAndEchoAll();
puts("Got second EOF.");
return 0;
}
当我 运行 它时,它按照我想要的方式工作。这是它的作用:
Reading and echoing STDIN until first EOF...
asdf
^Dasdf
Got first EOF. Now reading and echoing STDIN until second EOF...
fdsa
^Dfdsa
Got second EOF.
我正在尝试创建一个等效的 Haskell 程序。这是我的尝试:
readAndEchoAll :: IO ()
readAndEchoAll = do
buf <- getContents
putStr buf
main :: IO ()
main = do
putStrLn "Reading and echoing STDIN until first EOF..."
readAndEchoAll
putStrLn "Got first EOF. Now reading and echoing STDIN until second EOF..."
-- ???
readAndEchoAll
putStrLn "Got second EOF."
这行不通。这是它的作用:
Reading and echoing STDIN until first EOF...
asdf
^Dasdf
Got first EOF. Now reading and echoing STDIN until second EOF...
readtwice.hs: <stdin>: hGetContents: illegal operation (handle is closed)
如何使它像 C 程序一样工作? 我想我需要在我有 -- ???
的地方放一些 clearerr(stdin);
的等价物,但我不确定那个等价物是什么。
更新: 原来 clearerr
有点转移注意力,因为它是标准 C API 独有的。当使用 POSIX API 时,您可以再次阅读而无需执行任何等效操作。因此,与其让 Haskell 做任何额外的事情,我需要让它不做某事:一旦它看到 EOF 就不会阻止进一步读取。
对 GHC 源代码的快速搜索表明 clearerr()
根本没有被使用。但是,您可以再次打开 /dev/stdin
,因为看起来您正在使用 Linux 或类似的。试试这个:
stdin2 <- openFile "/dev/stdin" ReadMode
您也可以使用 hDuplicate
。看这里:Portably opening a handle to stdin many times in a single session
您不能使用 getContents
,因为 hGetContents
(半)关闭它传递的句柄并且 getContents
调用 hGetContents
。但是在 EOF 之后使用标准库中的大多数其他函数再次从句柄读取是没有问题的。这是一个不使用 getContents
:
读取所有字符的简单但低效的示例
import Control.Exception
import System.IO.Error
readAll = go [] where
handler cs err = if isEOFError err
then return (reverse cs)
else throwIO err
go cs = catch (do
c <- getChar
go (c:cs))
(handler cs)
main = do
all <- readAll
putStrLn $ "got: " ++ all
putStrLn "go again, mate"
all <- readAll
putStrLn $ "got: " ++ all
如果你想要更高的效率,有各种函数可用于读取 lines-at-a-time 或标准库中的其他大块,而不是一次读取一个字符。
我有以下 C 程序:
#include <stdio.h>
#include <unistd.h>
void readAndEchoAll(void) {
for(;;) {
char buf[100];
ssize_t size = read(STDIN_FILENO, buf, sizeof(buf));
if(size <= 0) {
return;
}
fwrite(buf, 1, size, stdout);
}
}
int main(void) {
puts("Reading and echoing STDIN until first EOF...");
readAndEchoAll();
puts("Got first EOF. Now reading and echoing STDIN until second EOF...");
readAndEchoAll();
puts("Got second EOF.");
return 0;
}
当我 运行 它时,它按照我想要的方式工作。这是它的作用:
Reading and echoing STDIN until first EOF...
asdf
^Dasdf
Got first EOF. Now reading and echoing STDIN until second EOF...
fdsa
^Dfdsa
Got second EOF.
我正在尝试创建一个等效的 Haskell 程序。这是我的尝试:
readAndEchoAll :: IO ()
readAndEchoAll = do
buf <- getContents
putStr buf
main :: IO ()
main = do
putStrLn "Reading and echoing STDIN until first EOF..."
readAndEchoAll
putStrLn "Got first EOF. Now reading and echoing STDIN until second EOF..."
-- ???
readAndEchoAll
putStrLn "Got second EOF."
这行不通。这是它的作用:
Reading and echoing STDIN until first EOF...
asdf
^Dasdf
Got first EOF. Now reading and echoing STDIN until second EOF...
readtwice.hs: <stdin>: hGetContents: illegal operation (handle is closed)
如何使它像 C 程序一样工作? 我想我需要在我有 -- ???
的地方放一些 clearerr(stdin);
的等价物,但我不确定那个等价物是什么。
更新: 原来 clearerr
有点转移注意力,因为它是标准 C API 独有的。当使用 POSIX API 时,您可以再次阅读而无需执行任何等效操作。因此,与其让 Haskell 做任何额外的事情,我需要让它不做某事:一旦它看到 EOF 就不会阻止进一步读取。
对 GHC 源代码的快速搜索表明 clearerr()
根本没有被使用。但是,您可以再次打开 /dev/stdin
,因为看起来您正在使用 Linux 或类似的。试试这个:
stdin2 <- openFile "/dev/stdin" ReadMode
您也可以使用 hDuplicate
。看这里:Portably opening a handle to stdin many times in a single session
您不能使用 getContents
,因为 hGetContents
(半)关闭它传递的句柄并且 getContents
调用 hGetContents
。但是在 EOF 之后使用标准库中的大多数其他函数再次从句柄读取是没有问题的。这是一个不使用 getContents
:
import Control.Exception
import System.IO.Error
readAll = go [] where
handler cs err = if isEOFError err
then return (reverse cs)
else throwIO err
go cs = catch (do
c <- getChar
go (c:cs))
(handler cs)
main = do
all <- readAll
putStrLn $ "got: " ++ all
putStrLn "go again, mate"
all <- readAll
putStrLn $ "got: " ++ all
如果你想要更高的效率,有各种函数可用于读取 lines-at-a-time 或标准库中的其他大块,而不是一次读取一个字符。