使用Boost将C *FILE转换为C++ iostream

4

我对C++还比较新,想要将一个*FILE(例如由popen()返回的)转换为iostream,以便与getline等函数一起使用。我发现了以下代码http://fw-geekycoder.blogspot.co.za/2011/06/how-to-convert-c-file-to-c-iostream.html,以及许多其他类似的代码,但编译器会抱怨boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_sink> bis(fd);boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_sink> bis(fd);


(Note: The original text contains HTML tags and links. Please keep them in the translation.)
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>

void write() {
    FILE* fp = fopen("whatever.txt", "w");
    if (fp == NULL) {
        perror("fopen error");
    }
    int fd = fileno(fp);
    boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_sink> bis(fd);
    std::ostream os(&bis);
    os << "Hello World!" << std::endl;

    fclose(fp);
}

void read() {
    FILE* fp = fopen("whatever.txt", "r");
    if (fp == NULL) {
        perror("fopen error");
    }
    int fd = fileno(fp);
    boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source> bis(fd);
    std::istream is(&bis);
    while (is) {
        std::string line;
        std::getline(is, line);
        std::cout << line << std::endl;
    }
    fclose(fp);
}

int main() {
    write();
    read();

    return 0;
}

看起来我的系统找到了boost,但好像API或其他东西发生了改变。问题出在哪里?这是我从Eclipse输出的结果:

make all 
Building file: ../src/boostPopenHandler.cpp
Invoking: GCC C++ Compiler
g++ -D__GXX_EXPERIMENTAL_CXX0X__ -I../../emdw/src -I../../patrecII/src -I../../ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++0x -MMD -MP -MF"src/boostPopenHandler.d" -MT"src/boostPopenHandler.d" -o"src/boostPopenHandler.o" "../src/boostPopenHandler.cpp"
In file included from ../src/boostPopenHandler.cpp:4:0:
/usr/include/boost/iostreams/device/file_descriptor.hpp: In instantiation of ‘boost::iostreams::file_descriptor_sink::file_descriptor_sink(const Path&, std::ios_base::openmode) [with Path = char; std::ios_base::openmode = std::_Ios_Openmode]’:
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = char; T = boost::iostreams::file_descriptor_sink; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::output_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:13:83:   required from here
/usr/include/boost/iostreams/device/file_descriptor.hpp:276:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
     { open(detail::path(path), mode); }
                                    ^
In file included from /usr/include/boost/iostreams/device/file_descriptor.hpp:26:0,
                 from ../src/boostPopenHandler.cpp:4:
/usr/include/boost/iostreams/detail/path.hpp:52:5: error:   initializing argument 1 of ‘boost::iostreams::detail::path::path(const char*)’ [-fpermissive]
     path(const char* p) : narrow_(p), wide_(), is_wide_(false) { }
     ^
In file included from ../src/boostPopenHandler.cpp:4:0:
/usr/include/boost/iostreams/device/file_descriptor.hpp: In instantiation of ‘boost::iostreams::file_descriptor_source::file_descriptor_source(const Path&, std::ios_base::openmode) [with Path = char; std::ios_base::openmode = std::_Ios_Openmode]’:
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = char; T = boost::iostreams::file_descriptor_source; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::input_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:26:85:   required from here
/usr/include/boost/iostreams/device/file_descriptor.hpp:194:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
     { open(detail::path(path), mode); }
                                    ^
In file included from /usr/include/boost/iostreams/device/file_descriptor.hpp:26:0,
                 from ../src/boostPopenHandler.cpp:4:
/usr/include/boost/iostreams/detail/path.hpp:52:5: error:   initializing argument 1 of ‘boost::iostreams::detail::path::path(const char*)’ [-fpermissive]
     path(const char* p) : narrow_(p), wide_(), is_wide_(false) { }
     ^
make: *** [src/boostPopenHandler.o] Error 1

编辑:
根据 Selçuk Cihan 的回答,我已将相关代码更改为:

boost::iostreams::file_descriptor_source fds(fd);
boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_sink> 
...
boost::iostreams::file_descriptor_source fds(fd);
boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source> 

但我仍然收到一系列编译错误:
**** Build of configuration Debug for project boostPopenHandler ****

make all 
Building file: ../src/boostPopenHandler.cpp
Invoking: GCC C++ Compiler
g++ -I../../emdw/src -I../../patrecII/src -I../../ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++0x -MMD -MP -MF"src/boostPopenHandler.d" -MT"src/boostPopenHandler.d" -o"src/boostPopenHandler.o" "../src/boostPopenHandler.cpp"
In file included from ../src/boostPopenHandler.cpp:4:0:
/usr/include/boost/iostreams/device/file_descriptor.hpp: In instantiation of ‘boost::iostreams::file_descriptor_source::file_descriptor_source(const Path&, std::ios_base::openmode) [with Path = int; std::ios_base::openmode = std::_Ios_Openmode]’:
../src/boostPopenHandler.cpp:13:52:   required from here
/usr/include/boost/iostreams/device/file_descriptor.hpp:194:36: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
     { open(detail::path(path), mode); }
                                    ^
In file included from /usr/include/boost/iostreams/device/file_descriptor.hpp:26:0,
                 from ../src/boostPopenHandler.cpp:4:
/usr/include/boost/iostreams/detail/path.hpp:52:5: error:   initializing argument 1 of ‘boost::iostreams::detail::path::path(const char*)’ [-fpermissive]
     path(const char* p) : narrow_(p), wide_(), is_wide_(false) { }
     ^
In file included from ../src/boostPopenHandler.cpp:4:0:
/usr/include/boost/iostreams/device/file_descriptor.hpp: In instantiation of ‘boost::iostreams::file_descriptor_sink::file_descriptor_sink(const Path&, std::ios_base::openmode) [with Path = boost::iostreams::file_descriptor_source; std::ios_base::openmode = std::_Ios_Openmode]’:
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = boost::iostreams::file_descriptor_source; T = boost::iostreams::file_descriptor_sink; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::output_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:14:84:   required from here
/usr/include/boost/iostreams/device/file_descriptor.hpp:276:36: error: no matching function for call to ‘boost::iostreams::detail::path::path(const boost::iostreams::file_descriptor_source&)’
     { open(detail::path(path), mode); }
                                    ^
/usr/include/boost/iostreams/device/file_descriptor.hpp:276:36: note: candidates are:
In file included from /usr/include/boost/iostreams/device/file_descriptor.hpp:26:0,
                 from ../src/boostPopenHandler.cpp:4:
/usr/include/boost/iostreams/detail/path.hpp:138:5: note: boost::iostreams::detail::path::path(const wstring&)
     path(const std::wstring&);
     ^
/usr/include/boost/iostreams/detail/path.hpp:138:5: note:   no known conversion for argument 1 from ‘const boost::iostreams::file_descriptor_source’ to ‘const wstring& {aka const std::basic_string<wchar_t>&}’
/usr/include/boost/iostreams/detail/path.hpp:70:5: note: boost::iostreams::detail::path::path(const boost::iostreams::detail::path&)
     path(const path& p) 
     ^
/usr/include/boost/iostreams/detail/path.hpp:70:5: note:   no known conversion for argument 1 from ‘const boost::iostreams::file_descriptor_source’ to ‘const boost::iostreams::detail::path&’
/usr/include/boost/iostreams/detail/path.hpp:64:14: note: template<class Path> boost::iostreams::detail::path::path(const Path&, typename Path::codecvt_type*)
     explicit path(const Path& p, typename Path::codecvt_type* = 0)
              ^
/usr/include/boost/iostreams/detail/path.hpp:64:14: note:   template argument deduction/substitution failed:
/usr/include/boost/iostreams/detail/path.hpp: In substitution of ‘template<class Path> boost::iostreams::detail::path::path(const Path&, typename Path::codecvt_type*) [with Path = boost::iostreams::file_descriptor_source]’:
/usr/include/boost/iostreams/device/file_descriptor.hpp:276:36:   required from ‘boost::iostreams::file_descriptor_sink::file_descriptor_sink(const Path&, std::ios_base::openmode) [with Path = boost::iostreams::file_descriptor_source; std::ios_base::openmode = std::_Ios_Openmode]’
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = boost::iostreams::file_descriptor_source; T = boost::iostreams::file_descriptor_sink; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::output_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:14:84:   required from here
/usr/include/boost/iostreams/detail/path.hpp:64:14: error: no type named ‘codecvt_type’ in ‘class boost::iostreams::file_descriptor_source’
/usr/include/boost/iostreams/device/file_descriptor.hpp: In instantiation of ‘boost::iostreams::file_descriptor_sink::file_descriptor_sink(const Path&, std::ios_base::openmode) [with Path = boost::iostreams::file_descriptor_source; std::ios_base::openmode = std::_Ios_Openmode]’:
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = boost::iostreams::file_descriptor_source; T = boost::iostreams::file_descriptor_sink; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::output_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:14:84:   required from here
/usr/include/boost/iostreams/detail/path.hpp:57:14: note: template<class Path> boost::iostreams::detail::path::path(const Path&, typename Path::external_string_type*)
     explicit path(const Path& p, typename Path::external_string_type* = 0)
              ^
/usr/include/boost/iostreams/detail/path.hpp:57:14: note:   template argument deduction/substitution failed:
/usr/include/boost/iostreams/detail/path.hpp: In substitution of ‘template<class Path> boost::iostreams::detail::path::path(const Path&, typename Path::external_string_type*) [with Path = boost::iostreams::file_descriptor_source]’:
/usr/include/boost/iostreams/device/file_descriptor.hpp:276:36:   required from ‘boost::iostreams::file_descriptor_sink::file_descriptor_sink(const Path&, std::ios_base::openmode) [with Path = boost::iostreams::file_descriptor_source; std::ios_base::openmode = std::_Ios_Openmode]’
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = boost::iostreams::file_descriptor_source; T = boost::iostreams::file_descriptor_sink; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::output_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:14:84:   required from here
/usr/include/boost/iostreams/detail/path.hpp:57:14: error: no type named ‘external_string_type’ in ‘class boost::iostreams::file_descriptor_source’
/usr/include/boost/iostreams/device/file_descriptor.hpp: In instantiation of ‘boost::iostreams::file_descriptor_sink::file_descriptor_sink(const Path&, std::ios_base::openmode) [with Path = boost::iostreams::file_descriptor_source; std::ios_base::openmode = std::_Ios_Openmode]’:
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   required from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(U100&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U100 = boost::iostreams::file_descriptor_source; T = boost::iostreams::file_descriptor_sink; Tr = std::char_traits<char>; Alloc = std::allocator<char>; Mode = boost::iostreams::output_seekable; typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
../src/boostPopenHandler.cpp:14:84:   required from here
/usr/include/boost/iostreams/detail/path.hpp:52:5: note: boost::iostreams::detail::path::path(const char*)
     path(const char* p) : narrow_(p), wide_(), is_wide_(false) { }
     ^
/usr/include/boost/iostreams/detail/path.hpp:52:5: note:   no known conversion for argument 1 from ‘const boost::iostreams::file_descriptor_source’ to ‘const char*’
/usr/include/boost/iostreams/detail/path.hpp:49:5: note: boost::iostreams::detail::path::path(const string&)
     path(const std::string& p) : narrow_(p), wide_(), is_wide_(false) { }
     ^
/usr/include/boost/iostreams/detail/path.hpp:49:5: note:   no known conversion for argument 1 from ‘const boost::iostreams::file_descriptor_source’ to ‘const string& {aka const std::basic_string<char>&}’
/usr/include/boost/iostreams/detail/path.hpp:46:5: note: boost::iostreams::detail::path::path()
     path() : narrow_(), wide_(), is_wide_(false) { }
     ^
/usr/include/boost/iostreams/detail/path.hpp:46:5: note:   candidate expects 0 arguments, 1 provided
make: *** [src/boostPopenHandler.o] Error 1

我不明白为什么编译器会尝试调用 boost::iostreams::file_descriptor_source::file_descriptor_source(const Path&, std::ios_base::openmode) 构造函数,即使你提供了一个 int fd。但这就是问题所在。 - Selçuk Cihan
你为什么要使用“-D__GXX_EXPERIMENTAL_CXX0X__”?那是未定义行为。当你使用“-std=c++0x”或类似选项时,编译器会自动设置它,并且如果没有适当的“-std”选项,它会导致错误。所以不要自己定义它。永远不要这样做。 - Jonathan Wakely
@Jonathan Wakely,我在一份指南中找到了这个内容,该指南解释了如何为C++ 11正确设置Eclipse。我不知道为什么该指南要特别说明这一点,因此我会遵循您的建议并将其删除。 - Simon Streicher
唉,也许Eclipse不够聪明,不知道“-std=c++0x”表示你正在使用C++11。也许曾经是这样,但我希望现在Eclipse已经修复了这个问题。 - Jonathan Wakely
有趣的是,我可以确认如果没有使用“-D__GXX_EXPERIMENTAL_CXX0X__”,Eclipse编译我的某些代码会出现问题。 - Simon Streicher
2个回答

5

哦,你应该首先声明一个file_descriptor_source,如下:

boost::iostreams::file_descriptor_source fds(fd);

然后就是你的流缓冲区。
boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source> bis(fds);

编辑:

抱歉造成混淆,具有int参数的ctor已被弃用,而且似乎您没有该ctor,否则您的代码将完美编译。这就是为什么上面提供的代码需要第二个必需参数,可以是boost::iostreams::never_close_handleboost::iostreams::close_handle之一。

因此应该这样写:

boost::iostreams::file_descriptor_source fds(fd, boost::iostreams::close_handle);

否则你仍会收到错误。file_descriptor_sink也需要同样的修复。
现在关于如何阅读错误信息:
引用块中说:
/usr/include/boost/iostreams/device/file_descriptor.hpp: 在实例化过程中‘boost::iostreams::file_descriptor_source::file_descriptor_source(const Path&, std::ios_base::openmode) [with Path = char; std::ios_base::openmode = std::_Ios_Openmode]’:
表示尝试使用模板参数char和std::_Ios_Openmode来实例化file_descriptor_source。
由于你只提供了一个整数,编译器尝试匹配该版本的构造函数,并未能成功进行转换。

我在尝试了你的建议之后仍然遇到编译错误,我已经在原始问题中记录了这些错误(因为输出内容相当长)。 - Simon Streicher
@SimonStreicher,你检查了我的编辑了吗?抱歉给你带来困惑。 - Selçuk Cihan
感谢您对特定错误的解释。我尝试了有关boost::iostreams::close_handle的最新建议,但现在编译器显示:undefined reference to boost::iostreams::file_descriptor_source::file_descriptor_source(int, boost::iostreams::file_descriptor_flags) - Simon Streicher
你应该告诉链接器关于boost库的信息,例如-lboost_iostreams - Selçuk Cihan
@ Selçuk Cihan。哦,谢谢,我以为boost_system包含了所有内容。现在它可以工作了! - Simon Streicher
你想使用 boos::iostreams::never_close_handle,因为 fclose 会自动关闭文件句柄。 - Brice M. Dempsey

0

你不需要Boost来完成这个。

想要将一个 *FILE(例如由popen()返回的文件)转换为iostream

使用pstreams代替(免责声明,我写了它,如果那很重要的话)。

一些编译器提供了从C文件创建streambuf的扩展,而无需使用Boost,例如GCC:

#include <ext/stdio_filebuf.h>
...
__gnu_cxx::stdio_filebuf<char> fb(fp, std::ios::out);
std::ostream os(&fb);

3
这不仅不是对这个问题的恰当回答,而且还在未声明自己的参与情况下宣传自己的项目! - Lightness Races in Orbit
2
那又怎样呢?我不是从pstreams里赚钱。但我确实拿着薪水在为GCC工作,我岂不应该宣传一下吗?;) - Jonathan Wakely
@Jonathan Wakely,谢谢,我确实尝试过了,但是没有找到一种简单的方法来在单个子进程中输出到stdin并从stdout流。我的最终目标是包装一个非常简单的输入输出cli程序。 - Simon Streicher
@Johnathan Wakely,如果是这样的话,我会尽快再试一次并报告我的发现。谢谢。 - Simon Streicher
1
作为额外的好处,@JonathanWakely的实现支持移动构造和赋值,而不像boost的实现版本1.81.0_1。 - Louis Langholtz
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接