POSIX 파일 설명자에서 C ++ fstream을 구성하는 방법은 무엇입니까?
기본적으로 fdopen ()의 C ++ 버전을 찾고 있습니다. 나는 이것에 대해 약간의 조사를했고 그것이 쉬울 것 같지만 매우 복잡한 것으로 밝혀진 것 중 하나입니다. 나는이 믿음에서 무언가를 놓치고 있는가 (즉, 정말 쉽다)? 그렇지 않다면 어딘가에 이것을 처리 할 수있는 좋은 라이브러리가 있습니까?
편집 : 예제 솔루션을 별도의 답변으로 옮겼습니다.
Éric Malenfant의 답변에서 :
AFAIK, 표준 C ++에서는이 작업을 수행 할 방법이 없습니다. 플랫폼에 따라 표준 라이브러리 구현은 파일 설명자를 입력으로 사용하는 fstream 생성자를 (비표준 확장으로) 제공 할 수 있습니다. (libstdc ++, IIRC의 경우) 또는 FILE *.
위의 관찰과 아래의 연구를 기반으로 두 가지 변형으로 작동하는 코드가 있습니다. 하나는 libstdc ++ 용이고 다른 하나는 Microsoft Visual C ++ 용입니다.
libstdc ++
다음 생성자 __gnu_cxx::stdio_filebuf
를 상속 std::basic_streambuf
하고 갖는 비표준 클래스 템플릿이 있습니다.
stdio_filebuf (int __fd, std::ios_base::openmode __mode, size_t __size=static_cast< size_t >(BUFSIZ))
with description 이 생성자는 파일 스트림 버퍼를 열린 POSIX 파일 설명자와 연관시킵니다.
POSIX 핸들 (1 행)을 전달하여 생성 한 다음 basic_streambuf (2 행)로 istream의 생성자에 전달합니다.
#include <ext/stdio_filebuf.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ofstream ofs("test.txt");
ofs << "Writing to a basic_ofstream object..." << endl;
ofs.close();
int posix_handle = fileno(::fopen("test.txt", "r"));
__gnu_cxx::stdio_filebuf<char> filebuf(posix_handle, std::ios::in); // 1
istream is(&filebuf); // 2
string line;
getline(is, line);
cout << "line: " << line << std::endl;
return 0;
}
마이크로 소프트 비주얼 C ++
POSIX 파일 설명자를 사용하는 ifstream 생성자의 비표준 버전 이 있었지만 현재 문서와 코드에서 모두 누락되었습니다 . FILE *을 사용하는 ifstream 생성자의 또 다른 비표준 버전이 있습니다.
explicit basic_ifstream(_Filet *_File)
: _Mybase(&_Filebuffer),
_Filebuffer(_File)
{ // construct with specified C stream
}
and it's not documented (I couldn't even find any old documentation where it would be present). We call it (line 1) with the parameter being the result of calling _fdopen to get C stream FILE* from POSIX file handle.
#include <cstdio>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ofstream ofs("test.txt");
ofs << "Writing to a basic_ofstream object..." << endl;
ofs.close();
int posix_handle = ::_fileno(::fopen("test.txt", "r"));
ifstream ifs(::_fdopen(posix_handle, "r")); // 1
string line;
getline(ifs, line);
ifs.close();
cout << "line: " << line << endl;
return 0;
}
AFAIK, there is no way to do this in standard C++. Depending on your platform, your implementation of the standard library may offer (as a nonstandard extension) a fstream constructor taking a file descriptor (This is the case for libstdc++, IIRC) or a FILE*
as an input.
Another alternative would be to use a boost::iostreams::file_descriptor device, which you could wrap in a boost::iostreams::stream if you want to have an std::stream interface to it.
There's a good chance your compiler offers a FILE-based fstream constructor, even though it's non-standard. For example:
FILE* f = fdopen(my_fd, "a");
std::fstream fstr(f);
fstr << "Greetings\n";
But as far as I know, there's no portable way to do this.
Part of the original (unstated) motivation of this question is to have the ability to pass data either between programs or between two parts of a test program using a safely created temporary file, but tmpnam() throws a warning in gcc, so I wanted to use mkstemp() instead. Here is a test program that I wrote based on the answer given by Éric Malenfant but using mkstemp() instead of fdopen(); this works on my Ubuntu system with Boost libraries installed:
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
using boost::iostreams::stream;
using boost::iostreams::file_descriptor_sink;
using boost::filesystem::path;
using boost::filesystem::exists;
using boost::filesystem::status;
using boost::filesystem::remove;
int main(int argc, const char *argv[]) {
char tmpTemplate[13];
strncpy(tmpTemplate, "/tmp/XXXXXX", 13);
stream<file_descriptor_sink> tmp(mkstemp(tmpTemplate));
assert(tmp.is_open());
tmp << "Hello mkstemp!" << std::endl;
tmp.close();
path tmpPath(tmpTemplate);
if (exists(status(tmpPath))) {
std::cout << "Output is in " << tmpPath.file_string() << std::endl;
std::string cmd("cat ");
cmd += tmpPath.file_string();
system(cmd.c_str());
std::cout << "Removing " << tmpPath.file_string() << std::endl;
remove(tmpPath);
}
}
I've tried the solution proposed above for libstdc++ by Piotr Dobrogost, and found that it had a painful flaw: Due to the lack of a proper move constructor for istream, it's very difficult to get the newly constructed istream object out of the creating function. Another issue with it is that it leaks a FILE object (even thought not the underlying posix file descriptor). Here's an alternative solution that avoids these issues:
#include <fstream>
#include <string>
#include <ext/stdio_filebuf.h>
#include <type_traits>
bool OpenFileForSequentialInput(ifstream& ifs, const string& fname)
{
ifs.open(fname.c_str(), ios::in);
if (! ifs.is_open()) {
return false;
}
using FilebufType = __gnu_cxx::stdio_filebuf<std::ifstream::char_type>;
static_assert( std::is_base_of<ifstream::__filebuf_type, FilebufType>::value &&
(sizeof(FilebufType) == sizeof(ifstream::__filebuf_type)),
"The filebuf type appears to have extra data members, the cast might be unsafe");
const int fd = static_cast<FilebufType*>(ifs.rdbuf())->fd();
assert(fd >= 0);
if (0 != posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
ifs.close();
return false;
}
return true;
}
The call to posix_fadvise() demonstrates a potential use. Also note that the example uses static_assert and using which are C++ 11, other than that it should build just fine in C++ 03 mode.
It actually is quite easy. Nicolai M. Josuttis has released fdstream
in conjunction with his book The C++ Standard Library - A Tutorial and Reference. You can find the 184 line implementation here.
My understanding is that there is no association with FILE pointers or file descriptors in the C++ iostream object model in order to keep code portable.
That said, I saw several places refer to the mds-utils or boost to help bridge that gap.
'Programing' 카테고리의 다른 글
git 태그 (또는이를 기반으로 한 GitHub 릴리스)의 날짜 변경 (0) | 2020.09.14 |
---|---|
하나의 .R 파일에 모든 함수를 정의하고 다른 .R 파일에서 호출합니다. (0) | 2020.09.14 |
string.h와 strings.h의 차이점 (0) | 2020.09.14 |
차이 무엇 (0) | 2020.09.14 |
신속하고 변형 된 구조체 (0) | 2020.09.14 |