Pages
Developer Documentation
On this page

KArchive

How do you store a lot of data in an archive easily from your code? KArchive, in sonic-frameworks-archive (find_package(KF6Archive), KF6::Archive), makes it quick and easy in Qt applications.

KArchive supports many archive formats: 7-Zip (K7Zip), ZIP (KZip), tar (KTar), ar (KAr) and Qt resource files (KRcc), so you can choose the format that suits your project.

Creating and opening an archive

An archive consists of:

  • a root directory
  • optional directories inside it
  • files in any directory

KArchive::writeDir() creates directories, and KArchive::writeFile() creates files, along with any directories in their path.

Both take paths: writeDir("emptydir/emptysubdir") and writeFile("somedir/subdir/world") create this structure:

hello.zip
├── emptydir/
│   └── emptysubdir/
└── somedir/
    └── subdir/
        └── world

Creating an archive with this structure is simple:

// Create a zip archive
KZip archive(QStringLiteral("hello.zip"));

// Open our archive for writing
if (archive.open(QIODevice::WriteOnly)) {
    // The archive is open, we can now write data
    archive.writeDir("emptydir/emptysubdir");
    archive.writeFile(QStringLiteral("somedir/subdir/world"), // File name
                      QByteArray("The whole world inside a hello."), // Data
                      0100644, // Permissions
                      QStringLiteral("owner"), // Owner
                      QStringLiteral("users")); // Group

    // Don't forget to close!
    archive.close();
}

If you know the path of the file, open the archive and read it like this:

if (archive.open(QIODevice::ReadOnly)) {
    const KArchiveDirectory *dir = archive.directory(); // the root directory
    const KArchiveFile *file = dir->file("somedir/subdir/world");
    if (!file) {
        qInfo() << "File not found!";
        return -1;
    }
    QByteArray data(file->data());
    qInfo() << data; // the file contents
}

Tip: data() reads the whole file into memory. To read it piece by piece, use createDevice() instead; you own the device it returns and must delete it:

std::unique_ptr<QIODevice> device(file->createDevice());
while (!device.get()->atEnd()) {
    qDebug() << device->readLine();
}

If you don't know the archive's structure in advance, use KArchiveEntry, the base class of KArchiveDirectory and KArchiveFile.

With it you can check whether an entry is a file or a directory:

// This example does not represent a full-fledged implementation.
if (archive.open(QIODevice::ReadOnly)) {
    const KArchiveDirectory *dir = archive.directory();
    const KArchiveEntry *entry = dir->entry("somedir/subdir/world");
    if (!entry) {
        qInfo() << "Entry not found!";
        return -1;
    }
    if (entry->isFile()) {
        const KArchiveFile *file = static_cast<const KArchiveFile *>(entry);
        QByteArray data(file->data());
        qDebug() << data;
    }
    // ...
}

Advanced uses

Working with compressed data

Besides archives, KArchive reads and writes compressed data on any device, such as a buffer or a socket, with KCompressionDevice. For example, you can save bandwidth when sending data over a network. It supports gzip, bzip2, xz, zstd and lzip compression.

This example, from sonic-frameworks-archive/examples/bzip2gzip, recompresses a bzip2 file with gzip (file is the opened input file, info its QFileInfo):

// Open the input archive
KCompressionDevice input(&file, false, KCompressionDevice::BZip2);
if (!input.open(QIODevice::ReadOnly)) {
    return 1;
}

QString outputFile = (info.completeBaseName() + QLatin1String(".gz"));

// Open the new output file
KCompressionDevice output(outputFile, KCompressionDevice::GZip);
if (!output.open(QIODevice::WriteOnly)) {
    return 1;
}

while (!input.atEnd()) {
    // Read and uncompress the data
    QByteArray data = input.read(512);

    // Write data like you would to any other QIODevice
    output.write(data);
}

input.close();
output.close();

KCompressionDevice::open() must have its result checked (the compiler warns otherwise).

Adapted for SonicDE from develop.kde.org/docs/features/karchive/ by Rohan Garg, Carl Schwan, Chris Holland, Mikhail Zolotukhin, Thiago Sueto, licensed under CC BY-SA 4.0.

Edit this page on GitHub

We use cookies to personalize content and to analyze our traffic. Please decide if you are willing to accept cookies from our website.