103

私は基本的に fdopen() の C++ バージョンを探しています。私はこれについて少し調査しましたが、これは簡単なはずのことの 1 つですが、非常に複雑であることが判明しました。この信念に欠けているものはありますか (つまり、本当に簡単です)? そうでない場合、これを処理するための優れたライブラリがどこかにありますか?

編集:私のソリューション例を別の回答に移動しました。

4

7 に答える 7

81

Éric Malenfant の回答から:

私の知る限り、標準の C++ でこれを行う方法はありません。プラットフォームによっては、標準ライブラリの実装が (非標準の拡張機能として) ファイル記述子を入力として受け取る fstream コンストラクターを提供する場合があります。(これは libstdc++、IIRC の場合です) または FILE*。

上記の観察と以下の私の調査に基づいて、2 つのバリアントで動作するコードがあります。1 つは libstdc++ 用で、もう 1 つは 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 として istream のコンストラクターに渡します (2 行目)。

#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
    }

そしてそれは文書化されていません(それが存在する古い文書さえ見つけることができませんでした)。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;
}
于 2011-03-09T23:41:14.353 に答える
44

AFAIK、標準のC++でこれを行う方法はありません。プラットフォームに応じて、標準ライブラリの実装は、ファイル記述子(libstdc ++、IIRCの場合)またはFILE*入力としてのfstreamコンストラクターを(非標準の拡張として)提供する場合があります。

もう1つの方法は、boost :: iostreams :: file_descriptorデバイスを使用することです。これは、std :: streamインターフェイスが必要な場合は、 boost :: iostreams::streamでラップできます。

于 2010-04-30T17:05:15.553 に答える
8

非標準であっても、コンパイラが FILE ベースの fstream コンストラクタを提供する可能性は十分にあります。例えば:

FILE* f = fdopen(my_fd, "a");
std::fstream fstr(f);
fstr << "Greetings\n";

しかし、私の知る限り、これを行う移植可能な方法はありません。

于 2010-04-30T17:26:25.457 に答える
8

この質問の元の (記述されていない) 動機の一部は、安全に作成された一時ファイルを使用して、プログラム間またはテスト プログラムの 2 つの部分間でデータを渡す機能を持つことですが、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);
  }
}
于 2013-02-25T19:12:41.443 に答える
-3

私の理解では、コードの移植性を維持するために、C++ iostream オブジェクト モデルには FILE ポインターまたはファイル記述子との関連付けはありません。

とはいえ、いくつかの場所でmds-utilsまたは boost を参照して、そのギャップを埋めるのに役立つのを見ました。

于 2010-04-30T17:07:17.823 に答える