首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在EOF之后再从标准输入中读取?

如何在EOF之后再从标准输入中读取?
EN

Stack Overflow用户
提问于 2019-05-21 01:18:25
回答 2查看 0关注 0票数 0

我有以下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就不要阻止进一步的读取。

EN

回答 2

Stack Overflow用户

发布于 2019-05-21 09:56:37

快速搜索GHC源代码表明,clearerr()根本没有使用它。因此,一旦文件到达EOF,它就永远在EOF。但是,您可以/dev/stdin再次打开,因为它看起来像您正在使用Linux或类似的。试试这个:

stdin2 <- openFile "/dev/stdin" ReadMode

你也可以使用hDuplicate。请参阅此处:在单个会话中多次打开stdin句柄

票数 0
EN

Stack Overflow用户

发布于 2019-05-21 10:28:50

你不能使用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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100009042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档