C-在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。

您不能使用getContents,因为hGetContents(semi-(关闭了传递的句柄,并且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

如果您想要更好的效率,则可以在标准库中使用各种功能来读取行或其他大块,而不是一个字符。

快速搜索GHC源代码显示clearerr()根本不使用。但是,您可以再次打开/dev/stdin,因为看起来您正在使用Linux或类似。尝试以下操作:

stdin2 <- openFile "/dev/stdin" ReadMode

您也可以使用hDuplicate。请参阅此处:在一次会话中,便便打开一个向STDIN的手柄

最新更新