从std::fstream获取文件* 是否有一个(跨平台)的方法从C++ STD::FSRUST.< /P>获取C文件*句柄? 我之所以问是因为我的C++库接受fScript,在一个特定的函数中,我想使用一个C文件库来接受文件*./p>

从std::fstream获取文件* 是否有一个(跨平台)的方法从C++ STD::FSRUST.< /P>获取C文件*句柄? 我之所以问是因为我的C++库接受fScript,在一个特定的函数中,我想使用一个C文件库来接受文件*./p>,c++,c,file,file-io,fstream,C++,C,File,File Io,Fstream,,你可以得到文件描述符,我忘记了方法是FDE还是GET()。我使用的实现提供了这样的方法,但我相信语言标准并不需要它们——标准不应该关心您的平台是否使用fd来处理文件 由此,您可以使用fdopen(fd,mode)获取文件* 但是,我认为标准同步STDIN/cin、STDOUT/cout和STDERR/cerr所需的机制不一定对您可见。因此,如果同时使用fstream和FILE*,缓冲可能会使您陷入困境 此外,如果fstream或文件关闭,它们可能会关闭底层fd,因此您需要确保在关闭任何一个之前

,你可以得到文件描述符,我忘记了方法是FDE还是GET()。我使用的实现提供了这样的方法,但我相信语言标准并不需要它们——标准不应该关心您的平台是否使用fd来处理文件

由此,您可以使用fdopen(fd,mode)获取文件*

但是,我认为标准同步STDIN/cin、STDOUT/cout和STDERR/cerr所需的机制不一定对您可见。因此,如果同时使用fstream和FILE*,缓冲可能会使您陷入困境


此外,如果fstream或文件关闭,它们可能会关闭底层fd,因此您需要确保在关闭任何一个之前刷新这两个fd。

简短的回答是否

原因是
std::fstream
不需要将
文件*
用作其实现的一部分。因此,即使您设法从
std::fstream
对象中提取文件描述符并手动构建文件对象,您也会遇到其他问题,因为现在将有两个缓冲对象写入同一文件描述符

真正的问题是,为什么要将
std::fstream
对象转换为
文件*

虽然我不推荐,但您可以尝试查找
funopen()

不幸的是,这不是一个POSIXAPI(它是一个BSD扩展),所以它的可移植性有问题。这也可能是为什么我找不到任何人用这样的对象包装了
std::stream

FILE *funopen(
              const void *cookie,
              int    (*readfn )(void *, char *, int),
              int    (*writefn)(void *, const char *, int),
              fpos_t (*seekfn) (void *, fpos_t, int),
              int    (*closefn)(void *)
             );

这允许您构建一个
文件
对象,并指定一些用于执行实际工作的函数。如果编写适当的函数,可以让它们从实际打开文件的
std::fstream
对象中读取。

没有标准化的方法。我认为这是因为C++标准化组不想假设文件句柄可以表示为fd.< /p>。 大多数平台似乎都提供了一些非标准的方法来实现这一点

提供了一个很好的情况描述,并提供了隐藏所有特定于平台的粗糙度的代码,至少对于GCC是这样。考虑到GCC上的这一点有多严重,我想如果可能的话,我会避免一起做这件事

更新:请参阅@Jettatura,我认为这是最好的答案(仅限Linux?)

原件:

(可能不是跨平台的,但很简单)

简化黑客入侵(dvorak答案),并查看此gcc扩展, 我有一个在
GCC
(至少4.8)和
clang
(至少3.3)上工作的解决方案

尝试处理
iostringstream

可以使用
fmemopen
istream
读取
fscanf
,但如果要结合C-reads和C++-reads,则每次读取后都需要大量的簿记和更新流的输入位置。我无法像上面那样将其转换为
cfile
函数。(可能每次读取后不断更新的
cfile
类才是最好的选择)

//黑客访问知道当前位置的istreambuf的受保护成员
字符*访问\u gptr(标准::基本\u流BUF&bs){
结构访问类:std::basic\u streambuf{
char*access_gptr()const{返回此->gptr();}
};
return((access_class*)(&bs))->access_gptr();
}
int main(){
标准:istringstream iss(“11 22 33”);
//读取C++方式
int j1;iss>>j1;
std::cout publiseekoff(ftell(文件)、iss.cur、iss.in);//从当前文件位置更新输入流位置。

std::cout在单线程POSIX应用程序中,您可以通过便携方式轻松获取fd编号:

int fd = dup(0);
close(fd);
// POSIX requires the next opened file descriptor to be fd.
std::fstream file(...);
// now fd has been opened again and is owned by file

如果此代码与打开文件描述符的其他线程发生冲突,则此方法将在多线程应用程序中中断。

在Linux中实现此操作的另一种方法:

#include <stdio.h>
#include <cassert>

template<class STREAM>
struct STDIOAdapter
{
    static FILE* yield(STREAM* stream)
    {
        assert(stream != NULL);

        static cookie_io_functions_t Cookies =
        {
            .read  = NULL,
            .write = cookieWrite,
            .seek  = NULL,
            .close = cookieClose
        };

        return fopencookie(stream, "w", Cookies);
    }

    ssize_t static cookieWrite(void* cookie,
        const char* buf,
        size_t size)
    {
        if(cookie == NULL)
            return -1;

        STREAM* writer = static_cast <STREAM*>(cookie);

        writer->write(buf, size);

        return size;
    }

    int static cookieClose(void* cookie)
    {
         return EOF;
    }
}; // STDIOAdapter
#包括
#包括
模板
结构标准适配器
{
静态文件*产量(流*流)
{
断言(流!=NULL);
静态cookie\u io\u函数\u t cookie=
{
.read=NULL,
.write=cookieWrite,
.seek=NULL,
.close=关闭
};
返回fopencookie(流,“w”,Cookies);
}
ssize_t静态cookieWrite(void*cookie,
常量char*buf,
尺寸(t尺寸)
{
if(cookie==NULL)
返回-1;
STREAM*writer=static_cast(cookie);
writer->write(基本单位,大小);
返回大小;
}
int静态cookieClose(void*cookie)
{
返回EOF;
}
};//标准适配器
用法,例如:

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/device/file.hpp>

using namespace boost::iostreams;

int main()
{   
    filtering_ostream out;
    out.push(boost::iostreams::bzip2_compressor());
    out.push(file_sink("my_file.txt"));

    FILE* fp = STDIOAdapter<filtering_ostream>::yield(&out);
    assert(fp > 0);

    fputs("Was up, Man", fp);

    fflush (fp);

    fclose(fp);

    return 1;
}
#包括
#包括
#包括
使用名称空间boost::iostreams;
int main()
{   
滤除干扰;
push(boost::iostreams::bzip2_compressor());
push(file_sink(“my_file.txt”);
FILE*fp=STDIOAdapter::yield(&out);
断言(fp>0);
fputs(“起来了,伙计”,fp);
fflush(fp);
fclose(fp);
返回1;
}

有一种方法可以从
fstream
获取文件描述符,然后将其转换为
文件*
(通过
fdopen
)。我个人认为
文件*
没有任何必要,但使用文件描述符,您可以做许多有趣的事情,例如重定向(
dup2

解决方案:

#定义私有-公共
#定义受保护的公共
#包括
#未定义私有
#未定义保护
std::ifstream文件(“某个文件”);
auto fno=file.\M_filebuf.\M_file.fd();
最后一个字符串适用于libstdc++。如果使用其他库,则需要对其进行一点反向工程

这是一个肮脏的把戏,它会暴露fstream的所有私人和公共成员。如果
// hack to access the protected member of istreambuf that know the current position
char* access_gptr(std::basic_streambuf<char, std::char_traits<char>>& bs){
    struct access_class : std::basic_streambuf<char, std::char_traits<char>>{
        char* access_gptr() const{return this->gptr();}
    };
    return ((access_class*)(&bs))->access_gptr();
}

int main(){
    std::istringstream iss("11 22 33");
    // read the C++ way
    int j1; iss >> j1;
    std::cout << j1 << std::endl;

    // read the C way
    float j2;

    char* buf = access_gptr(*iss.rdbuf()); // get current position
    size_t buf_size = iss.rdbuf()->in_avail(); // get remaining characters
    FILE* file = fmemopen(buf, buf_size, "r"); // open buffer memory as FILE*
    fscanf(file, "%f", &j2); // finally!
    iss.rdbuf()->pubseekoff(ftell(file), iss.cur, iss.in); // update input stream position from current FILE position.

    std::cout << "j2 = " << j2 << std::endl;

    // read again the C++ way
    int j3; iss >> j3;
    std::cout << "j3 = " << j3 << std::endl;
}
int fd = dup(0);
close(fd);
// POSIX requires the next opened file descriptor to be fd.
std::fstream file(...);
// now fd has been opened again and is owned by file
#include <stdio.h>
#include <cassert>

template<class STREAM>
struct STDIOAdapter
{
    static FILE* yield(STREAM* stream)
    {
        assert(stream != NULL);

        static cookie_io_functions_t Cookies =
        {
            .read  = NULL,
            .write = cookieWrite,
            .seek  = NULL,
            .close = cookieClose
        };

        return fopencookie(stream, "w", Cookies);
    }

    ssize_t static cookieWrite(void* cookie,
        const char* buf,
        size_t size)
    {
        if(cookie == NULL)
            return -1;

        STREAM* writer = static_cast <STREAM*>(cookie);

        writer->write(buf, size);

        return size;
    }

    int static cookieClose(void* cookie)
    {
         return EOF;
    }
}; // STDIOAdapter
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/device/file.hpp>

using namespace boost::iostreams;

int main()
{   
    filtering_ostream out;
    out.push(boost::iostreams::bzip2_compressor());
    out.push(file_sink("my_file.txt"));

    FILE* fp = STDIOAdapter<filtering_ostream>::yield(&out);
    assert(fp > 0);

    fputs("Was up, Man", fp);

    fflush (fp);

    fclose(fp);

    return 1;
}
#define private public
#define protected public
#include <fstream>
#undef private
#undef protected

std::ifstream file("some file");
auto fno = file._M_filebuf._M_file.fd();