我有以下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的手柄