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