2011-03-05 18 views
8

È possibile utilizzare un QFile come un std :: iostream? Sono abbastanza sicuro che ci debba essere un wrapper là fuori. La domanda è dove?Come usare un QFile con std :: iostream?

Ho un altro libs, che richiede un parametro di input come std :: istream, ma nel mio programma ho solo un file Q a questo punto.

+3

[That] (http://stackoverflow.com/questions/848269/mixing-qt-with-stl-and-boost-are-there-any-bridges-to-make-it-easy/856812#856812) sembra una soluzione, ma richiede Boost. –

+0

Potresti accettare una soluzione non portabile e se sì quale piattaforma ti serve su cui lavorare? –

+0

È boost :: iostream intercambiabile con std :: basic_stream? –

risposta

5

mi si avvicinò con la mia soluzione (che utilizza la stessa idea Stephen Chu ha suggerito)

#include <iostream> 
#include <fstream> 
#include <cstdio> 

#include <QtCore> 

using namespace std; 

void externalLibFunction(istream & input_stream) { 
    copy(istream_iterator<string>(input_stream), 
     istream_iterator<string>(), 
     ostream_iterator<string>(cout, " ")); 
} 

ifstream QFileToifstream(QFile & file) { 
    Q_ASSERT(file.isReadable());   
    return ifstream(::_fdopen(file.handle(), "r")); 
} 

int main(int argc, char ** argv) 
{ 
    QFile file("a file"); 
    file.open(QIODevice::WriteOnly); 
    file.write(QString("some string").toLatin1()); 
    file.close(); 
    file.open(QIODevice::ReadOnly); 
    std::ifstream ifs(QFileToifstream(file)); 
    externalLibFunction(ifs); 
} 

uscita:

some string 

Questo codice utilizza std :: ifstream mossa costruttore (C++ caratteristica x0) specificato nel 27.9.1.7 costruttori basic_ifstream sezione di Working Draft, Standard for Programming Language C++:

basic_ifstream(basic_ifstream&& rhs);
Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_filebuf. Next basic_istream::set_rdbuf(&sb) is called to install the contained basic_filebuf.

Vedere How to return an fstream (C++0x) per la discussione su questo argomento.

+0

Per la riga 'ifstream (:: _ fdopen (file.handle(), "r")); 'Ho ottenuto:' errore: nessuna funzione di abbinamento per la chiamata a 'std :: basic_ifstream :: basic_ifstream (FILE *)' std :: ifstream fileInputStream (:: _ fdopen (testPatternPng. handle(), "r")); ' – Troyseph

0

Se non ti interessa molto per le prestazioni puoi sempre leggere tutto dal file e scaricarlo in un std::stringstream e quindi passarlo alla tua libreria. (o viceversa, buffer tutto a un stringstream e quindi scrivere su un QFile)

A parte questo, non sembra che i due possano interagire. In ogni caso, le operazioni da Qt a STL sono spesso causa di oscuri bug e sottili incoerenze se la versione di STL con cui è stato compilato Qt è diversa in qualsiasi modo dalla versione di STL che si sta utilizzando. Questo può accadere ad esempio se cambi la versione di Visual Studio.

+1

Grazie per il tuo suggerimento, ma stringstream non è un'opzione perché il file può diventare piuttosto grande. Quindi leggere tutti i dati nella memoria è abbastanza brutto. –

4

Se l'oggetto QFile che si ottiene non è già aperto per la lettura, è possibile ottenere il nome file da esso e aprire un oggetto ifstream.

Se è già aperto, è possibile ottenere file handle/descrittore con handle() e passare da lì. Non esiste un modo portatile per ottenere un flusso dalla maniglia della piattaforma. Dovrai trovare una soluzione alternativa per le tue piattaforme.

+0

Il solo nome del file non funzionerà con le risorse Qt. Il metodo handle() funzionerà se il QFile sta puntando su una risorsa? – galinette

+0

In realtà, puoi utilizzare Boost.IOStreams per creare un iostream indipendente dalla piattaforma: fd: innanzitutto crei un buffer di flusso: 'boost :: iostreams :: stream_buffer streambuf (handle)' , quindi passa il puntatore al buffer del flusso sul tuo nuovo 'std :: iostream (& streambuf)'. –

6

mi si avvicinò con la mia soluzione utilizzando il seguente codice:

#include <ios> 
#include <QIODevice> 

class QStdStreamBuf : public std::streambuf 
{ 
public: 
    QStdStreamBuf(QIODevice *dev) : std::streambuf(), m_dev(dev) 
    { 
     // Initialize get pointer. This should be zero so that underflow is called upon first read. 
     this->setg(0, 0, 0); 
    } 

protected: 
virtual std::streamsize xsgetn(std::streambuf::char_type *str, std::streamsize n) 
{ 
    return m_dev->read(str, n); 
} 

virtual std::streamsize xsputn(const std::streambuf::char_type *str, std::streamsize n) 
{ 
    return m_dev->write(str, n); 
} 

virtual std::streambuf::pos_type seekoff(std::streambuf::off_type off, std::ios_base::seekdir dir, std::ios_base::openmode /*__mode*/) 
{ 
    switch(dir) 
    { 
     case std::ios_base::beg: 
      break; 
     case std::ios_base::end: 
      off = m_dev->size() - off; 
      break; 
     case std::ios_base::cur: 
      off = m_dev->pos() + off; 
      break; 
    } 
    if(m_dev->seek(off)) 
     return m_dev->pos(); 
    else 
     return std::streambuf::pos_type(std::streambuf::off_type(-1)); 
} 
virtual std::streambuf::pos_type seekpos(std::streambuf::pos_type off, std::ios_base::openmode /*__mode*/) 
{ 
    if(m_dev->seek(off)) 
     return m_dev->pos(); 
    else 
     return std::streambuf::pos_type(std::streambuf::off_type(-1)); 
} 

virtual std::streambuf::int_type underflow() 
{ 
    // Read enough bytes to fill the buffer. 
    std::streamsize len = sgetn(m_inbuf, sizeof(m_inbuf)/sizeof(m_inbuf[0])); 

    // Since the input buffer content is now valid (or is new) 
    // the get pointer should be initialized (or reset). 
    setg(m_inbuf, m_inbuf, m_inbuf + len); 

    // If nothing was read, then the end is here. 
    if(len == 0) 
     return traits_type::eof(); 

    // Return the first character. 
    return traits_type::not_eof(m_inbuf[0]); 
} 


private: 
    static const std::streamsize BUFFER_SIZE = 1024; 
    std::streambuf::char_type m_inbuf[BUFFER_SIZE]; 
    QIODevice *m_dev; 
}; 

class QStdIStream : public std::istream 
{ 
public: 
    QStdIStream(QIODevice *dev) : std::istream(m_buf = new QStdStreamBuf(dev)) {} 
    virtual ~QStdIStream() 
    { 
     rdbuf(0); 
     delete m_buf; 
    } 

private: 
    QStdStreamBuf * m_buf; 
}; 

mi funziona bene per la lettura di file locali. Non l'ho provato per scrivere file. Questo codice non è sicuramente perfetto ma funziona.

Problemi correlati