label:
In the previous chapter, we introduced the use of the two classes QFile and QFileInfo. We mentioned that QIODevice provides basic operations such as read () and readLine (). At the same time, Qt also provides a higher level of operations: QDataStream for binary streams and QTextStream for text streams. In this section, we will explain the use of QDataStream and some tips. The next chapter is related to QTextStream.
QDataStream provides serialization of binary data based on QIODevice. The data stream is a binary stream that does not depend on the underlying operating system, CPU, or byte order (big endian or little endian) at all. For example, a data stream written on a PC with a Windows platform can be directly read on a SPARC machine running Solaris without any processing. Since the data stream is a binary stream, we can also directly read and write unencoded binary data, such as images, video, and audio.
QDataStream can access basic C ++ types, such as int, char, short, etc., as well as complex data types, such as custom classes. In fact, QDataStream implements the storage of classes by dividing complex classes into many basic units.
Combined with QIODevice, QDataStream can easily read and write files, network sockets, etc. Let's start with the code:
QFile file ("file.dat");
file.open (QIODevice :: WriteOnly);
QDataStream out (& file);
out << QString ("the answer is");
out << (qint32) 42;
In this code, we first open a file named file.dat (note that we did not check whether the file was opened successfully for simplicity, which is not allowed in the official program). Then, we pass the pointer of the file object we just created to a QDataStream instance out. Similar to std :: cout standard output stream, QDataStream also overloads the output redirection << operator. The following code is very simple: output "the answer is" and the number 42 to the data stream (if you don't understand the meaning of this sentence, this is the answer to the ultimate question of the universe; -P Please search "Guide to the Galaxy" ). Since our out object is built on file, it is equivalent to writing the answer to the ultimate question of the universe into file.
It should be pointed out that it is best to use Qt integers for reading and writing, such as qint32 in the program. This guarantees the same behavior on any platform and any compiler.
Let's take an example to see how Qt stores data. For example, char * character string, when stored, the character string including the length of the \ 0 terminator (32-bit integer) will be stored first, then the content of the string and the terminator \ 0. When reading, first read the entire length as a 32-bit integer, and then take out the entire string content according to this length.
However, if you run this code directly, you will get a blank file.dat without writing any data. This is because our file is not closed properly. For performance reasons, data is only actually written when the file is closed. Therefore, we must add a line of code at the end:
file.close (); // If you don't want to close the file, you can use file.flush ();
Re-run the program, it is OK.
We have obtained the answer to the ultimate question of the universe. Below, we will read this answer:
QFile file ("file.dat");
file.open (QIODevice :: ReadOnly);
QDataStream in (& file);
QString str;
qint32 a;
in >> str >> a;
There is nothing to say about this code. The only thing to note is that you must read the data in the order of writing. In other words, the order in which program data is written must be defined in advance. In this example, we write the string first, and then write the number, then the string is read first, and then the number. If the order is reversed, the behavior of the program is uncertain, and in severe cases it will directly cause the program to crash.
Since the binary stream is pure byte data, the problem is that if different versions of the program are read in different ways (as mentioned earlier, Qt guarantees that the read and write content is consistent, but it does not guarantee between different Qt versions The same), the data will be wrong. Therefore, we must provide a mechanism to ensure consistency between different versions. Usually, we will use the following code to write:
QFile file ("file.dat");
file.open (QIODevice :: WriteOnly);
QDataStream out (& file);
// Write magic number and version
out << (quint32) 0xA0B0C0D0;
out << (qint32) 123;
out.setVersion (QDataStream :: Qt_4_0);
// data input
out << lots_of_interesting_data;
Here, we have added two lines of code:
out << (quint32) 0xA0B0C0D0;
Used to write magic numbers. The so-called magic number is a technique often used in binary output. The binary format is unreadable by humans, and usually has the same suffix name (such as dat), so there is no way to distinguish which two binary files are legal. Therefore, the binary format we define usually has a magic number to identify the legality of the file. In this example, we write 0xA0B0C0D0 at the beginning of the file. When reading, we first check whether this number is 0xA0B0C0D0. If it is not, the file is not in a recognizable format, so there is no need to continue reading. Generally, binary files will have such a magic number. For example, the magic number of Java class files is 0xCAFEBABE, which can be viewed using a binary viewer. The magic number is a 32-bit unsigned integer, so we use quint32 to get a platform-independent 32-bit unsigned integer.
The next line,
out << (qint32) 123;
Is the version of the identification file. We use magic numbers to identify the type of file to determine whether the file is legal. However, there may be differences between different versions of the file: we may save the integer in the first version and the string in the second version. In order to identify different versions, we can only write the version to a file. For example, our version is now 123.
The following line is still relevant:
out.setVersion (QDataStream :: Qt_4_8);
The above sentence is the version number of the file, but the way of reading between different versions of Qt may be different. In this way, we have to specify which version of Qt to read. Here, we specify to read the content in Qt 4.8 format.
After we write the file like this, we need to add a series of judgments when reading:
QFile file ("file.dat");
file.open (QIODevice :: ReadOnly);
QDataStream in (& file);
// check the magic number
quint32 magic;
in >> magic;
if (magic! = 0xA0B0C0D0) {
return BAD_FILE_FORMAT;
}
// Check the version
qint32 version;
in >> version;
if (version <100) {
return BAD_FILE_TOO_OLD;
}
if (version> 123) {
return BAD_FILE_TOO_NEW;
}
if (version <= 110) {
in.setVersion (QDataStream :: Qt_3_2);
} else {
in.setVersion (QDataStream :: Qt_4_0);
}
// read data
in >> lots_of_interesting_data;
if (version> = 120) {
in >> data_new_in_version_1_2;
}
in >> other_interesting_data;
This code is carried out according to the previous explanation. First read the magic number to check whether the file is legal. If it is legal, reading the file version: less than 100 or greater than 123 is not supported. If it is within the supported version range (100 <= version <= 123), when it is less than or equal to 110, read in the format of Qt_3_2, otherwise read in the format of Qt_4_0. After setting these parameters, start reading data.
So far, we have introduced relevant content about QDataStream. So, since QIODevice provides functions like read (), readLine (), why do we need QDataStream? What is the difference between QDataStream and QIODevice? The difference is that QDataStream provides the form of a stream, and its performance is generally better than calling the original API directly. Let's look at what is the form of the stream through the following piece of code:
QFile file ("file.dat");
file.open (QIODevice :: ReadWrite);
QDataStream stream (& file);
QString str = "the answer is 42";
QString strout;
stream << str;
file.flush ();
stream >> strout;
In this code, we first write data to the file, and then read the data. Any questions? After running, you will find that strout is actually empty. Why is it not read? Haven't we added file.flush (); statement? The reason is not whether the file is written, but because we are using "stream". The so-called flow, just like water flow, its cursor will move backwards with the output. After using the << operator to output, the cursor of the stream has reached the end. At this time, you can read it again, of course, you can't read anything. So you need to set the cursor to the position of 0 again after output to continue reading. The specific code snippet is as follows:
stream << str;
stream.device ()-> seek (0);
stream >> strout;
http://blog.csdn.net/u013007900/article/details/46459613
Qt learning of binary file reading and writing