Differences and examples between QFile, QByteArray QDataStream and QTextStream in Qt

In Qt, QFile, QByteArray, QDataStream and QTextStream are commonly used file and data processing classes.

Main functions and differences

  1. QFile:

QFile is an I/O device used to read and write text and binary files and resources. You can use QFile on its own, or more conveniently with QTextStream or QDataStream.

The file name is usually passed in the constructor, but it can be set at any time using setFileName(). QFile expects the file delimiter to be ‘/’, regardless of operating system. The use of delimiters (e.g. ”) is not supported.

You can use exists() to check whether a file exists, and remove() to delete a file. (More advanced file system related operations are provided by QFileInfo and QDir.)

Files are opened using open(), closed using close(), and refreshed using flush(). Usually QDataStream or QTextStream is used to read and write data, but you can also use the function read()< inherited by QIODevice /code>, readLine(), readAll(), write() to operate. QFile also inherits getChar(), putChar() and ungetChar(), which can be operated character by character.

Use size() to get the size of the file. You can use pos() to get the current file location, or use seek() to move to a new file location. If the end of the file has been reached, atEnd() returns true.

  1. QByteArray:

The QByteArray class provides a byte array.
QByteArray can be used to store raw bytes (including ‘\0’) and traditional 8-bit ‘\0’ terminated strings. Using QByteArray is more convenient than using const char *. Behind the scenes, it always ensures that data is followed by a ‘\0’ terminator and uses implicit sharing (copy-on-write) to reduce memory usage and avoid unnecessary data copies.
In addition to QByteArray, Qt also provides the QString class for storing string data. For most cases, the QString class should be used. It stores 16-bit Unicode characters, making it easy to store non-ASCII/non-Latin-1 characters in applications. Additionally, QString is used extensively in the Qt API. The two main cases where QByteArray is suitable are when raw binary data needs to be stored, and when memory protection is critical (for example, in Qt for Embedded Linux).
One way to initialize a QByteArray is to pass a const char * to its constructor. For example, the following code creates a byte array of size 5 containing the data “Hello”:

 QByteArray ba("Hello");

Although size() is 5, the byte array also reserves an extra ‘\0’ character at the end so that when using functions that require pointers to the underlying data (such as calling data()), the data pointed to is guaranteed It ends with ‘\0’.
QByteArray makes a deep copy of the const char* data so you can modify it later without side effects. (If for performance reasons you don’t want to make a deep copy of character data, use QByteArray::fromRawData() instead.)

Another way is to use resize() to set the size of the array and initialize the data byte by byte. QByteArray uses 0-based indexing, just like C++ arrays. To access the byte at a specific index position, you can use the operator. For non-const byte arrays, the operator returns a byte reference that can be used on the left side of the assignment. For example:

 QByteArray ba;
  ba.resize(5);
  ba[0] = 0x3c;
  ba[1] = 0xb8;
  ba[2] = 0x64;
  ba[3] = 0x18;
  ba[4] = 0xca;

For read-only access, use the alternative syntax of at():

 for (int i = 0; i < ba.size(); + + i) {<!-- -->
      if (ba.at(i) >= 'a' & amp; & amp; ba.at(i) <= 'f')
          cout << "Found character in range [a-f]" << endl;
  }

at() is probably faster than operator because it never causes a deep copy to occur.
To extract multiple bytes at once, use left(), right(), or mid().
QByteArray can embed ‘\0’ bytes. The size() function always returns the size of the entire array, including the embedded ‘\0’ bytes, but excluding the terminating ‘\0’ added by the QByteArray. For example:

 QByteArray ba1("ca\0r\0t");
  ba1.size(); // Return 2.
  ba1.constData(); // Returns "ca" with terminating \0.

  QByteArray ba2("ca\0r\0t", 3);
  ba2.size(); // Return 3.
  ba2.constData(); // Returns "ca\0" with terminating \0.

  QByteArray ba3("ca\0r\0t", 4);
  ba3.size(); // Return 4.
  ba3.constData(); // Returns "ca\0r" with terminating \0.

  const char cart[] = {<!-- -->'c', 'a', '\0', 'r', '\0', ' t'};
  QByteArray ba4(QByteArray::fromRawData(cart, 6));
  ba4.size(); // Return 6.
  ba4.constData(); // Returns "ca\0r\0t" without terminating \0.

If you want to get the length of the data up to but not including the first ‘\0’ character, you can call qstrlen() on the byte array.
After calling resize(), the value of the newly allocated bytes is undefined. To set all bytes to a specific value, call fill().
To get a pointer to the actual character data, call data() or constData(). These functions return a pointer to the beginning of the data. This pointer is guaranteed to remain valid until a non-const function is called on the QByteArray. It is also guaranteed that the data ends with ‘\0’ bytes unless the QByteArray is created from raw data. QByteArray provides this ‘\0’ byte automatically and is not counted in size().
QByteArray provides the following basic functions to modify byte data: append(), prepend(), insert(), replace() and remove(). For example:

 QByteArray x("and");
  x.prepend("rock "); // x == "rock and"
  x.append(" roll"); // x == "rock and roll"
  x.replace(5, 3, " & amp;"); // x == "rock & amp; roll"

The first two parameters of the replace() and remove() functions are the position to start erasing and the number of bytes that should be erased.
When appending data to a non-empty array the array is reallocated and the new data is copied into it. You can avoid this behavior by calling reserve(), which preallocates a certain amount of memory. You can also call capacity() to find out how much memory the QByteArray actually allocated. Data appended to an empty array will not be copied.
It is often required to remove whitespace characters (‘\\
‘, ‘\t’, ”, etc.) from a byte array. If you want to remove whitespace characters from both ends of a QByteArray, use trimmed(). If you want to remove whitespace characters from both ends of a QByteArray and replace multiple consecutive whitespace characters with a single whitespace character in the byte array, use simplified().
If you want to find all occurrences of a specific character or substring in a QByteArray, you can use indexOf() or lastIndexOf(). The former searches forward from a given index position, the latter searches backward. If a character or substring is found, both return its index position; otherwise, they return -1. For example, the following is a typical loop to find a specific substring:

 QByteArray ba("We must be <b>bold</b>, very <b>bold</b>");
  int j = 0;
  while ((j = ba.indexOf("<b>", j)) != -1) {<!-- -->
      cout << "Found <b> tag at index position " << j << endl;
       + + j;
  }

If you just want to check whether a QByteArray contains a specific character or substring, use contains(). If you want to find out how many times a specific character or substring appears in a byte array, use count(). If you want to replace all occurrences of a specific value with another value, use one of the replace() overloads that takes two parameters.
QByteArrays can be compared using overloaded operators such as operator<(), operator<=(), operator==(), operator>=(). The comparison is based only on numeric values of characters, which is very fast, but not what one would expect. For sorting user interface strings, QString::localeAwareCompare() is a better choice.

For historical reasons, QByteArray distinguishes between null byte arrays and null byte arrays. An empty byte array is a byte array that is initialized by using QByteArray’s default constructor or by passing (const char *)0 to the constructor. Any byte array of size 0 is an empty byte array. An empty byte array is not necessarily a null byte array:

 QByteArray().isNull(); // Return true
  QByteArray().isEmpty(); // Return true

  QByteArray("").isNull(); // Return false
  QByteArray("").isEmpty(); // Return true

  QByteArray("abc").isNull(); // Return false
  QByteArray("abc").isEmpty(); // Return false

Except for the isNull() function, all other functions treat a null byte array as the same as an empty byte array. For example, for a null byte array, data() returns a pointer to the ‘\0’ character (a non-null pointer), and QByteArray() is equal to QByteArray(“”). We recommend always using isEmpty() and avoiding isNull().

  1. QDataStream:

The QDataStream class provides the functionality to serialize binary data to QIODevice.
A data stream is a stream of binary-encoded information that is completely independent of the host computer’s operating system, CPU, or byte order. For example, a data stream written by a Windows PC can be read by a Sun SPARC running a Solaris system.
You can also use data streams to read and write raw, unencoded binary data. If you need a “parsed” input stream, see QTextStream.
The QDataStream class implements the serialization of C++ basic data types (such as char, short, int, char *, etc.). Serialization of more complex data is accomplished by breaking the data into basic units.

Data flow works closely with QIODevice. A QIODevice represents an input/output medium from which data can be read or written to. The QFile class is an example of an I/O device.

Example (writing binary data to a data stream):

 QFile file("file.dat");
  file.open(QIODevice::WriteOnly);
  QDataStream out( & amp;file); // Serialize data to file
  out << QString("the answer is"); // Serialized string
  out << (qint32)42; // serialized integer

Example (read binary data from data stream):

 QFile file("file.dat");
  file.open(QIODevice::ReadOnly);
  QDataStream in( & amp;file); // Read serialized data from the file
  QString str;
  qint32 a;
  in >> str >> a; // Extract "the answer is" and 42

Each item in the write stream is written in a predefined binary format that depends on the type of item. Supported Qt types include QBrush, QColor, QDateTime, QFont, QPixmap, QString, QVariant, etc. For a complete list of all Qt types that support data streams, see Serializing Qt Data Types.
For integers, it’s always best to cast them to a Qt integer type for writing, and read back into the same Qt integer type. This ensures you get the integer size you want and insulates you from compiler and platform differences.
As an example, a char* string is written as a 32-bit integer equal to the length of the string, including ‘\0’ bytes, followed by all the characters of the string, including ‘\0’ bytes. When reading a char * string, 4 bytes are first read to create a 32-bit length value, and then the same number of characters are read to create a char * string containing the ‘\0’ terminator.
The initial I/O device is usually set in the constructor, but can be changed using setDevice(). If the end of the data has been reached (or no I/O device has been set), atEnd() will return true.

Version Control
The binary format of QDataStream has evolved since Qt 1.0, and will likely continue to evolve in response to changes in Qt. When inputting or outputting complex types, it is very important to ensure that the same version (version()) is used when reading and writing. If you need forward and backward compatibility, you can hardcode the version number in your application:

 stream.setVersion(QDataStream::Qt_4_0);

If you are generating a new binary data format, such as a document file format created by your application, you can use QDataStream to write the data in a portable format. Typically you would write a short header containing an identifying string and a version number to leave room for future extensions. For example:

 QFile file("file.xxx");
  file.open(QIODevice::WriteOnly);
  QDataStream out( & amp;file);

  // Write the header containing the "magic number" and version number
  out << (quint32)0xA0B0C0D0;
  out << (qint32)123;

  out.setVersion(QDataStream::Qt_4_0);

  //Input data
  out << lots_of_interest_data;

Then use the following code to read:

 QFile file("file.xxx");
  file.open(QIODevice::ReadOnly);
  QDataStream ( & amp;infile);

  // Read and check header
  quint32 magic;
  in >> magic;
  if (magic != 0xA0B0C0D0)
      return XXX_BAD_FILE_FORMAT;

  //Read version number
  qint32 version;
  in >> version;
  if (version < 100)
      return XXX_FILE_TOO_OLD;
  if (version > 123)
      return XXX_BAD_FILE_TOO_NEW;

  if (version <= 110)
      in.setVersion(QDataStream::Qt_3_2);
  else
      in.setVersion(QDataStream::Qt_4_0);

  // Get data
  in >> lots_of_interesting_data;
  if (version >= 120)
      in >> data_new_in_XXX_version_1_2;
  in >> other_interesting_data;

When serializing data, you can choose which byte order to use. The default setting is big endian (most significant bit first). Changing it to little endian breaks portability (unless the reading side is also changed to little endian). We recommend keeping this setting unless there are special needs.
Reading and writing raw binary data
You may want to read/write your own raw binary data directly from the data stream. Data can be read from a stream into a preallocated char * using readRawData(). Similarly, data can be written to a stream using writeRawData(). Note that any encoding/decoding of the data must be done by yourself.
Another pair of similar functions are readBytes() and writeBytes(). The differences from the original function are: readBytes() reads a quint32, treats it as the length to read, and reads that number of bytes into a preallocated char*; writeBytes() writes the containing data quint32 of the length, then the data itself. Note that any encoding/decoding of the data (other than length quint32) must be done by yourself.

  1. QTextStream

The QTextStream class provides a convenient interface for reading and writing text.
QTextStream can operate on QIODevice, QByteArray or QString. Using QTextStream’s stream operators, you can easily read and write words, lines, and numbers. For generating text, QTextStream supports formatting options for field padding and alignment, as well as formatting of numbers. Example:

 QFile data("output.txt");
  if (data.open(QFile::WriteOnly | QFile::Truncate)) {<!-- -->
      QTextStream out( & amp;data);
      out << "Result: " << qSetFieldWidth(10) << left << 3.14 << 2.7;
      // Output "Result: 3.14 2.7 "
  }

QTextStream is also commonly used to read console input and write console output. QTextStream is locale aware and will automatically use the correct codec to decode standard input. Example:

 QTextStream stream(stdin);
  QString line;
  while (stream.readLineInto( & amp;line)) {<!-- -->
      ...
  }

In addition to using the constructor of QTextStream, you can also set the device or string that QTextStream operates on by calling setDevice() or setString(). You can locate a certain position by calling seek(). When there is no data to read, calling atEnd() will return true. If flush() is called, QTextStream will clear all data in its write buffer to the device and call flush() on the device.
Internally, QTextStream uses Unicode-based buffers and QTextCodec is used to automatically support different character sets. By default, reading and writing use QTextCodec::codecForLocale(), but the codec can also be set by calling setCodec(). Automatic Unicode detection is also supported. When this feature is enabled (default behavior), QTextStream will detect the BOM (byte order mark) of UTF-16 or UTF-32 and switch to the appropriate UTF codec when reading. QTextStream does not write BOM by default, but can be enabled by calling setGenerateByteOrderMark(true). The codec is disabled when QTextStream operates directly on QString.

There are three common ways to use QTextStream to read text files:

  • Read in blocks, by calling readLine() or readAll().
  • Read word by word. QTextStream supports streaming reading into QString, QByteArray and char* buffers. Words are separated by spaces, and leading spaces are automatically skipped.
  • Read character by character, by streaming into QChar or char type. This approach is often used to conveniently handle input regardless of character encoding and end-of-line semantics. To skip spaces, call skipWhiteSpace(). \

Since text streams use buffers, you should not use the superclass’s implementation to read from the stream. For example, if you have a QFile and read from it directly using QFile::readLine() without using a stream, the internal position of the text stream will be out of sync with the position of the file.
By default, QTextStream automatically detects the base representation of numbers when reading numbers from a text stream. For example, if a number starts with “0x”, it is considered in hexadecimal form. If it starts with a number from 1-9, it is considered in decimal form, and so on. You can disable automatic detection by setting the base of an integer by calling setIntegerBase(). Example:

 QTextStream in("0x50 0x20");
  int firstNumber, secondNumber;

  in >> firstNumber; // firstNumber == 80
  in >> dec >> secondNumber; // secondNumber == 0

  char ch;
  in >> ch; // ch == 'x'

QTextStream supports many formatting options for generating text. You can set the field width and padding character by calling setFieldWidth() and setPadChar(). Use setFieldAlignment() to set the alignment within each field. For real numbers, you can call setRealNumberNotation() and setRealNumberPrecision() to set the representation (intelligent representation, scientific representation, fixed-point representation) and precision (number of digits) of the generated number. Some other number format options can also be set through setNumberFlags().

As in the standard C++ library, QTextStream also defines several global manipulation functions:

Manipulation function Description
bin Same as setIntegerBase(2).
oct Same as setIntegerBase(8).
dec Same as setIntegerBase(10).
hex Same as setIntegerBase(16).
showbase and setNumberFlags(numberFlags()
forcesign with setNumberFlags(numberFlags()
forcepoint with setNumberFlags(numberFlags()
noshowbase Same as setNumberFlags(numberFlags() & amp; ~ShowBase).
noforcesign Same as setNumberFlags(numberFlags() & amp ; ~ForceSign).
noforcepoint Same as setNumberFlags(numberFlags() & amp; ~ForcePoint).
uppercasebase with setNumberFlags(numberFlags()
uppercasedigits with setNumberFlags(numberFlags()
lowercasebase Same as setNumberFlags(numberFlags() & amp; ~UppercaseBase).
lowercasedigits Same as setNumberFlags(numberFlags() & amp; ~UppercaseDigits).
fixed Same as setRealNumberNotation(FixedNotation).
scientific Same as setRealNumberNotation(ScientificNotation).
left Same as setFieldAlignment(AlignLeft).
right Same as setFieldAlignment(AlignRight).
center Same as setFieldAlignment(AlignCenter).
endl The same as operator<<(\\ ’) and flush().
flush Same as flush().
reset Same as reset().
ws Same as skipWhiteSpace().
bom Same as setGenerateByteOrderMark(true).

In addition, Qt provides three global manipulators with parameters: qSetFieldWidth(), qSetPadChar() and qSetRealNumberPrecision().

The summary is that QFile is used for file reading and writing operations, QByteArray is used for processing binary data, and QDataStream is used for serialization and decoding of binary data. Serialization, and QTextStream is used for reading, writing and processing text data. Each of them has different functions and applicable scenarios. Choose the appropriate class for operation according to specific needs.

Usage and examples

When using QFile, QByteArray, QDataStream and QTextStream in Qt, you can use their member functions as follows:

  1. Usage examples of QFile:
#include <QFile>
#include <QDebug>
#include <QApplication>

int main(int argc, char *argv[])
{<!-- -->
QApplication a(argc, argv);
    //Create a QFile object
    QFile file("data.txt");

 // Open file for writing
    if (file.open(QIODevice::WriteOnly))
    {<!-- -->
        //Write data to file
        QString data = "Hello, World!";
        file.write(data.toUtf8());

        // close file
        file.close();
    }

    // Open file for reading
    if (file.open(QIODevice::ReadOnly))
    {<!-- -->
        //Read the data in the file
        QByteArray data = file.readAll();
        
        //Convert byte array to string and output
        QString str(data);
        qDebug() << str;

        // close file
        file.close();
    }

    return a.exec();
}
  1. Usage examples of QByteArray:
#include <QByteArray>
#include <QDebug>
#include <QApplication>

int main(int argc, char *argv[])
{<!-- -->
QApplication a(argc, argv);
    //Create a QByteArray object
    QByteArray byteArray;

    //Add data to byte array
    byteArray.append("Hello");
    byteArray.append(" ");
    byteArray.append("World!");

    // Output the data in the byte array
    qDebug() << byteArray;

    // Clear byte array
    byteArray.clear();

    return a.exec();
}
  1. Usage examples of QDataStream:
#include <QDataStream>
#include <QFile>
#include <QDebug>
#include <QApplication>

int main(int argc, char *argv[])
{<!-- -->
QApplication a(argc, argv);
    //Create a QFile object
    QFile file("data.bin");

    // Open file for writing
    if (file.open(QIODevice::WriteOnly))
    {<!-- -->
        //Create a QDataStream object and pass in the QFile object
        QDataStream stream( & amp;file);
        
        //Write an integer to the stream
        int value = 42;
        stream << value;

        // close file
        file.close();
    }

    // Open file for reading
    if (file.open(QIODevice::ReadOnly))
    {<!-- -->
        //Create a QDataStream object and pass in the QFile object
        QDataStream stream( & amp;file);

        //Read integer from stream
        int value;
        stream >> value;

        // Output the integer obtained
        qDebug() << value;

        //Close file
        file.close();
    }

    return a.exec();
}
  1. Usage examples of QTextStream:
#include <QTextStream>
#include <QFile>
#include <QDebug>
#include <QApplication>

int main(int argc, char *argv[])
{<!-- -->
QApplication a(argc, argv);
    //Create a QFile object
    QFile file("data.txt");

    // Open file for writing
    if (file.open(QIODevice::WriteOnly | QIODevice::Text))
    {<!-- -->
        //Create a QTextStream object and pass in the QFile object
        QTextStream stream( & amp;file);

        //Write text to the stream
        stream << "Hello, World!";

        // close file
        file.close();
    }

    // Open file for reading
    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
    {<!-- -->
        //Create a QTextStream object and pass in the QFile object
        QTextStream stream( & amp;file);

        //Read text from the stream
        QString text = stream.readAll();

        // Output the read text
        qDebug() << text;

        // close file
        file.close();
    }

    return a.exec();
}

The examples use QFile to read and write files, QByteArray to process byte arrays, QDataStream to serialize and deserialize binary data, and QTextStream to read and write text data.

Comprehensive usage

#include <QFile>
#include <QByteArray>
#include <QDataStream>
#include <QTextStream>
#include <QDebug>
#include <QApplication>


int main(int argc, char *argv[])
{<!-- -->
QApplication a(argc, argv);
    //Create a QByteArray object
    QByteArray byteArray;

    //Add data to byte array
    byteArray.append("Hello, World!");

    //Create a QFile object
    QFile file("data.bin");

     // Open file for writing
    if (file.open(QIODevice::WriteOnly))
    {<!-- -->
        //Create a QDataStream object and pass in the QFile object
        QDataStream dataStream( & amp;file);

        //Write byte array to stream
        dataStream << byteArray;

        // close file
        file.close();
    }

    // Open file for reading
    if (file.open(QIODevice::ReadOnly))
    {<!-- -->
        //Create a QDataStream object and pass in the QFile object
        QDataStream dataStream( & amp;file);

        //Create a new QByteArray object
        QByteArray newDataArray;

        //Read byte array from stream
        dataStream >> newDataArray;

        //Create a QTextStream object
        QTextStream textStream( & amp;newDataArray);

        //Read string data
        QString text = textStream.readAll();

        // Output the read string
        qDebug() << text;

        // close file
        file.close();
    }

    return a.exec();
}

Output results


In the example, first create a QByteArray object and add data to it. Then, write this byte array to a file (using QDataStream) and close the file. Next, open the file again and read a byte array from it using QDataStream. Finally, use QTextStream to read the string data in the byte array and output it to the console.

syntaxbug.com © 2021 All Rights Reserved.