Domanda

Sono fondamentalmente alla ricerca di un C ++ versione di fdopen (). Ho fatto un po 'di ricerche su questo ed è una di quelle cose che sembra che dovrebbe essere facile, ma si rivela essere molto complicato. Mi sto perdendo qualcosa in questa convinzione (vale a dire che è davvero facile)? In caso contrario, c'è una biblioteca buona là fuori da qualche parte per gestire questo?

EDIT:. Mossi mia soluzione ad esempio ad una risposta separata

È stato utile?

Soluzione

Dalla risposta data da Éric Malenfant:

  

Per quanto ne sappia, non esiste un modo per fare questo in   standard di C ++. Dipende dal tuo   piattaforma, l'implementazione della   libreria standard può offrire (come   estensione non standard) un fstream   costruttore di prendere un descrittore di file   come input. (Questo è il caso di   libstdc ++, IIRC) o un file *.

Sulla base di osservazioni di cui sopra e la mia ricerca di seguito c'è il codice di lavoro in due varianti; uno per libstdc ++ e un altro per Microsoft Visual C ++.


libstdc ++

Non c'è non standard __gnu_cxx::stdio_filebuf modello di classe che eredita std::basic_streambuf e ha il seguente costruttore

stdio_filebuf (int __fd, std::ios_base::openmode __mode, size_t __size=static_cast< size_t >(BUFSIZ)) 

con la descrizione Questo costruttore associa un buffer flusso di file con un descrittore di file POSIX aperto.

crearla passando maniglia POSIX (linea 1) e poi passarlo al costruttore di istream come basic_streambuf (linea 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;
}

Microsoft Visual C ++

Ci deve essere utilizzato di costruttore di ifstream prendendo POSIX descrittore di file, ma che manca sia dal noreferrer attuali documenti e dal codice. C'è un'altra versione non standard di ifstream costruttore presa FILE *

explicit basic_ifstream(_Filet *_File)
    : _Mybase(&_Filebuffer),
        _Filebuffer(_File)
    {   // construct with specified C stream
    }

e non è documentato (non riuscivo nemmeno a trovare alcuna documentazione vecchia dove sarebbe stato presente). Noi lo chiamiamo (linea 1) con il parametro è il risultato della chiamata _ fdopen per ottenere C flusso di file * dall'impugnatura di file POSIX.

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

Altri suggerimenti

Per quanto ne sappia, non esiste un modo per fare questo in C ++ standard. A seconda della piattaforma, l'implementazione della libreria standard può offrire (come estensione non standard) un costruttore fstream prendendo un descrittore di file (questo è il caso di libstdc ++, IIRC) o un FILE* come ingresso.

Un'altra alternativa sarebbe quella di utilizzare un spinta :: :: dispositivo iostreams file_descriptor , che si può avvolgere in un boost :: :: iostreams flusso se si vuole avere un'interfaccia std :: flusso ad esso.

C'è una buona probabilità che le vostre offerte compilatore un costruttore fstream basato su file, anche se è non standard. Ad esempio:

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

Ma per quanto ne so, non c'è modo portatile per fare questo.

Una parte del (non dichiarata) la motivazione di questa domanda originale è quello di avere la capacità di passare i dati sia tra programmi o tra due parti di un programma di test utilizzando un file temporaneo creato in modo sicuro, ma tmpnam () lancia un avvertimento a gcc, così ho voluto usare mkstemp (), invece. Ecco un programma di test che ho scritto sulla base della risposta data da Éric Malenfant ma utilizzando mkstemp () al posto di fdopen (); Questo funziona su mio sistema Ubuntu con le librerie Boost installati:

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

Ho provato la soluzione proposta sopra per libstdc ++ da Piotr Dobrogost, e ha scoperto che aveva un difetto doloroso: A causa della mancanza di una vera e propria costruttore mossa per istream, è molto difficile ottenere l'oggetto istream di nuova costruzione fuori la funzione di creazione. Un altro problema con esso è che perde un oggetto FILE (anche pensato non sottostante posix descrittore di file). Ecco una soluzione alternativa che evita questi problemi:

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

La chiamata a posix_fadvise () dimostra un potenziale utilizzo. Si noti inoltre che l'esempio utilizza static_assert e con , che sono C ++ 11, diverso da quello che si deve costruire bene in modalità 03 C ++.

In realtà è abbastanza facile. Nicolai M. Josuttis ha rilasciato fdstream in concomitanza con il suo libro La libreria standard C ++ - Un tutorial e una di riferimento . È possibile trovare l'attuazione 184 linea di qui .

La mia comprensione è che non c'è alcuna associazione con i puntatori di file o descrittori di file nel modello di oggetti C ++ iostream al fine di mantenere il codice portabile.

Detto questo, ho visto molti posti si riferiscono alla MDS-utils o impulso per colmare questa lacuna.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top