기본적으로 fdopen ()의 C ++ 버전을 찾고 있습니다. 나는 이것에 대해 약간의 조사를했고 그것이 쉬울 것 같지만 매우 복잡한 것으로 밝혀진 것 중 하나입니다. 나는이 믿음에서 무언가를 놓치고 있는가 (즉, 정말 쉽다)? 그렇지 않다면 어딘가에 이것을 처리 할 수있는 좋은 라이브러리가 있습니까?
편집 : 예제 솔루션을 별도의 답변으로 옮겼습니다.
mmap
파일을 처리하고 그 내용을 바이트 배열로 노출 할 수 있습니다 .
기본적으로 fdopen ()의 C ++ 버전을 찾고 있습니다. 나는 이것에 대해 약간의 조사를했고 그것이 쉬울 것 같지만 매우 복잡한 것으로 밝혀진 것 중 하나입니다. 나는이 믿음에서 무언가를 놓치고 있는가 (즉, 정말 쉽다)? 그렇지 않다면 어딘가에 이것을 처리 할 수있는 좋은 라이브러리가 있습니까?
편집 : 예제 솔루션을 별도의 답변으로 옮겼습니다.
mmap
파일을 처리하고 그 내용을 바이트 배열로 노출 할 수 있습니다 .
답변:
Éric Malenfant의 답변에서 :
AFAIK, 표준 C ++에서는이 작업을 수행 할 방법이 없습니다. 플랫폼에 따라 표준 라이브러리 구현은 파일 설명자를 입력으로 사용하는 fstream 생성자를 (비표준 확장으로) 제공 할 수 있습니다. (libstdc ++, IIRC의 경우) 또는 FILE *.
위의 관찰과 아래의 연구를 기반으로 두 가지 변형으로 작동하는 코드가 있습니다. 하나는 libstdc ++ 용이고 다른 하나는 Microsoft Visual C ++ 용입니다.
다음 생성자 __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;
}
POSIX 파일 설명자를 사용하는 ifstream 생성자의 비표준 버전 이 있었지만 현재 문서와 코드에서 모두 누락되었습니다 . FILE *을 사용하는 ifstream 생성자의 또 다른 비표준 버전이 있습니다.
explicit basic_ifstream(_Filet *_File)
: _Mybase(&_Filebuffer),
_Filebuffer(_File)
{ // construct with specified C stream
}
문서화되지 않았습니다 (존재할 오래된 문서도 찾을 수 없었습니다). POSIX 파일 핸들에서 C 스트림 FILE *을 가져 오기 위해 _fdopen 을 호출 한 결과 인 매개 변수를 사용하여 (라인 1)이라고 부릅니다 .
#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;
}
std::cout
구현을 살펴 보는 것은 좋은 생각입니다. stdio_filebuf
과 의 차이점이 무엇인지 궁금합니다 stdio_sync_filebuf
.
AFAIK, 표준 C ++에서는이 작업을 수행 할 방법이 없습니다. 플랫폼에 따라 표준 라이브러리 구현은 파일 설명자 (libstdc ++, IIRC의 경우) 또는 FILE*
입력을 사용 하는 fstream 생성자를 비표준 확장으로 제공 할 수 있습니다 .
또 다른 대안은 boost :: iostreams :: file_descriptor 장치 를 사용하는 것입니다. std :: stream 인터페이스를 사용하려면 boost :: iostreams :: stream으로 래핑 할 수 있습니다.
비표준 임에도 불구하고 컴파일러가 FILE 기반 fstream 생성자를 제공 할 가능성이 높습니다. 예를 들면 :
FILE* f = fdopen(my_fd, "a");
std::fstream fstr(f);
fstr << "Greetings\n";
그러나 내가 아는 한, 이것을 할 수있는 휴대용 방법은 없습니다.
이 질문의 원래 (명시되지 않은) 동기의 일부는 안전하게 생성 된 임시 파일을 사용하여 프로그램간에 또는 테스트 프로그램의 두 부분간에 데이터를 전달할 수있는 기능을 갖는 것이지만 tmpnam ()은 gcc에서 경고를 표시하므로 원했습니다. 대신 mkstemp ()를 사용하십시오. 다음은 Éric Malenfant의 답변을 기반으로 작성했지만 fdopen () 대신 mkstemp ()를 사용하여 작성한 테스트 프로그램입니다. 이것은 Boost 라이브러리가 설치된 Ubuntu 시스템에서 작동합니다.
#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);
}
}
실제로 아주 쉽습니다. Nicolai M. Josuttis는 fdstream
그의 저서 The C ++ Standard Library-A Tutorial and Reference 와 함께 발표 했습니다 . 여기 에서 184 라인 구현을 찾을 수 있습니다 .
위의 Piotr Dobrogost가 libstdc ++에 대해 제안한 솔루션을 시도한 결과 고통스러운 결함이 있음을 발견했습니다. istream에 대한 적절한 이동 생성자가 없기 때문에 새로 구성된 istream 개체를 생성 기능에서 가져 오는 것이 매우 어렵습니다. . 또 다른 문제는 FILE 객체가 누출된다는 것입니다 (기본 posix 파일 설명자가 아니라고 생각하더라도). 다음은 이러한 문제를 방지하는 대체 솔루션입니다.
#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;
}
posix_fadvise ()에 대한 호출은 잠재적 인 사용을 보여줍니다. 또한이 예제는 static_assert 를 사용 하고 C ++ 11을 사용 하는 것 외에는 C ++ 03 모드에서 잘 빌드되어야합니다.
내 이해는 코드 이식성을 유지하기 위해 C ++ iostream 개체 모델의 FILE 포인터 또는 파일 설명자와 관련이 없다는 것입니다.
즉, 여러 곳에서 mds-utils 또는 boost를 참조하여 그 격차를 해소하는 것을 보았습니다 .