Serializing a QFile
I'm looking for a natural way to read and write QFile objects from a QIODevice. I think this is a serialization problem. I don't think it can be done. Who can prove me wrong? (Please! :-))
I'm writing a QIODevice wrapper for a protocol that transports files reliably via IP multicast. When the protocol engine receives a file, it informs the QIODevice. The QIODevice can raise the readyRead() signal. I'd like to be able to read a QFile from this QIODevice. For example, if the new file is "/tmp/foo.txt", I should be able to read QFile("/tmp/foo.txt") from this QIODevice.
Similarly, I should be able to write QFile objects into the QIODevice so that the protocol engine can transmit them.
Is this possible with Qt 4.x? I don't believe it is. I don't believe that QFile is serializable.
The best solution so far is to read and write file names from the QIODevice. I can wrap the QFile ctor around one line read from the QIODevice, where a "line" is the name of a file. I can write file names into the QIODevice and have it make the protocol engine transmit the file.
By "serializing", do you mean "encoding for transmission via the protocol"? In my mind, a file's data is an array of bytes, so I see it as "serialized" by definition. Please correct me if I'm wrong.
Ok, for now I'll assume that you meant "encoding for transmission", and also assume that your custom QIODevice provides the encoding/decoding functions.
You could set it up like this, where you implement the encoding/decoding in CustomDevice::writeData() and CustomDevice::readData()
// Receive a file
QFile receivedFile( customDevice.getFileName() );
// Send a file
customDevice.setFileName( fileToSend.fileName() );
Some other info that might be useful:
- A QFile IS a QIODevice
- Qt has a built-in data serializer, designed to work closely with QIODevices. They have examples on how it interacts with QFiles: http://qt-project.org/doc/qt-4.8/qdatastream.html
Thanks for the detailed response, JKSH.
What I propose to do is read a QFile object, not the contents of a file, from my QIODevice.
The protocol sends files. Let's say it sends foo.txt. It notifies the receiver app when all of foo.txt has been received. As a response to that notification, I can want to create an unopened QFile("foo.txt") and enqueue it the QIODevice's read buffer. When the receiver app responds to the readyRead() signal, it can read the QIODevice and deserialize the bytes into QFile("foo.txt"). The QFile never goes out onto the network.
I still don't see a way to serialize QFile objects. QIODevice doesn't have a method for reading or writing QObjects. There may be no way to do what I want.
Ah, I think I understand your intentions better now. So you want to serialize the object that manages the file, not the file data itself?
I'm not sure if that's possible, or recommended... After all, a QFile is a QObject, and QObjects are designed to be uncopyable; serializing+transmitting an object -- even if it's on the same machine -- is a fancy way of making a copy.
In any case, deserializing any object involves constructing a new object. What do you wish to achieve, that can't be done by simply constructing a new QFile from the received file's path? (e.g. the last paragraph of your original post)
I think the only transferable properties that the QFile has are the file name, its open flags, current open/closed state, and seek position (a QString, QFlags<OpenModeFlag>, bool, and qint64). The first is meaningful at the receiving end only if the same file exists at the same location on that machine. The other parameters could be used to put a receiver local QFile wrapping that file in a similar state assuming the file is identical to the sending system's file... otherwise all bets are off.
Since you are talking about serialising an unopened QFile then all you need send is the QFile::filename(). There are obvious methods to send a QString.
Thanks, JKSH and ChrisW67, for your advice. I solved the problem as I predicted, with file names instead of QFiles. To send a file, write the name of the file terminated with a newline into my QIODevice. On the receiving side, use the QIODevice's readLine() to read the name of the least recently received file.
The work in progress is part of a "suite of mobile ad hoc networking applications for mobile phones":https://github.com/MobileEmergencyCommunicationsProject/manetsuite. Look at "qnormfiletransport.h":https://github.com/MobileEmergencyCommunicationsProject/manetsuite/blob/master/qnormtransport/qnormfiletransport.h and "qnormfiletransport.cpp":https://github.com/MobileEmergencyCommunicationsProject/manetsuite/blob/master/qnormtransport/qnormfiletransport.cpp.
Sounds brittle to me.
I'd look into using QDataStream instead. First send the file name as a string, and then the contents as a QByteArray. That way, you will have no problems with issues like the file itself containing newlines too...