Дмитрий
Дмитрий18. Mai 2019 15:29

Fb3-Dateileser auf Qt Creator

Vor einiger Zeit habe ich ein fb2-Reader-Projekt veröffentlicht, bei dessen Bearbeitung ich herausfand, dass dieses Format veraltet ist. Daher fing ich an, neue Formate zu beherrschen und entschied mich für fb3, das fb2-Empfängerformat. Im Laufe der Arbeit bin ich auf einige Probleme gestoßen, die nicht vollständig gelöst wurden. Darüber hinaus wurde das Format trotz der Tatsache, dass bereits Bücher in fb3 erscheinen, noch nicht endgültig genehmigt. Obwohl Bücher bereits erscheinen. Daher habe ich mich entschlossen, das Programm in seiner jetzigen Form zu veröffentlichen und über meine Erfolge und Misserfolge zu sprechen. Anschließend plane ich eine neue Version mit Unterstützung des epub-Formats.


fb3

Die fb3-Datei ist ein Zip-Container, der Buchelemente enthält. Daher habe ich den folgenden Algorithmus implementiert. Entpacken Sie alle Dateien in einen temporären Ordner und lesen Sie alle notwendigen Elemente daraus.

if(name.endsWith(".fb3"))
{
    QString s = thisName;
    QString nameUn = QStandardPaths::standardLocations(QStandardPaths::TempLocation).at(0)
                    + "/dmreader/" + s;

    if(!openerTextFiles::UnZip(name, nameUn)) // распаковка архива
        qDebug() << "файл " << name << " не открыт";
    else
    {
        // извлекаем содержимое
        openerTextFiles::openFBFile(nameUn + "/fb3/body.xml", &text, &content); 
        // помещаем содержимое в окно textBrowser
        ui->textBrowser->setText(text);
        ui->textBrowser->verticalScrollBar()->setValue(0);
        ui->comboBoxContent->insertItems(0, content);
        ui->comboBoxContent->setCurrentIndex(-1);
        this->setWindowTitle(content.first());
    }
}

Die Beispieldatei enthält:

Der fb3-Ordner enthält grundlegende Informationen, insbesondere zwei wichtige body.xml-Elemente - den Text des Buches und description.xml - die Anmerkungen zum Buch, die den Hauptblöcken der fb2-Datei entsprechen. Der Ordner img enthält die Illustrationen des Buches.
Die body.xml-Struktur nach einigen Änderungen an der fb2-Struktur. Die Änderungen zielen darauf ab, die Funktionalität zu erweitern und die Struktur zu vereinfachen. Tags ol, ul, li hinzugefügt, um Listen zu erstellen. blockquote - Anführungszeichen, em - Textakzente (kursiv), pre - Block aus vorformatiertem Text, identisch mit HTML. Die Tags underline (unterstrichen) und space (sparse) können mit den folgenden Ersetzungen implementiert werden:

<span style=\"text-decoration:underline;\">
<span style=\"letter-spacing:5px;\">

Auch das Notensystem wurde leicht modifiziert, darauf gehe ich nicht näher ein.
Deutlich verändert das System der Illustrationen. Im Text mit Tag Es gibt Links zu den Nummern der Bilder. Um Bilder anzuzeigen, müssen Sie zunächst die Links zu diesen aus der Datei "/_rels/body.xml.rels" auslesen. Dazu erstelle ich ein Array img_fb3 vom Typ QHash , wobei die erste Zeile ein Link zum Bild im Text ist, die zweite der Pfad zum Bild im img-Verzeichnis.
Das img-Tag wird so verarbeitet

if( sr.name().toString() == "img" ) // расположение рисунков fb3
{
    if(sr.attributes().count() > 0)
    {
        if( sr.attributes().at(0).name().toString() == "src" )
            book->append("<p align=\"center\"><img src=\""
                         + filerels + "/"
                         + img_fb3.take( sr.attributes().at(0).value().toString() )
                         + "\" alt=\"рисунок\"" + "/></p>");   
        else
            qDebug() << "img src ошибка";
    }
    break;
}

img_fb3 wird so gefüllt

if(sr.name().toString() == "fb3-body") // ссылки на картинки fb3
{
    QFile fr(filerels + "/_rels/body.xml.rels" );
    if (!fr.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "файл body.xml.rels не открыт";
        break;
    }

    QXmlStreamReader srr(&fr);
    while( !srr.atEnd() )
    {
        switch( srr.readNext() )
        {
        case QXmlStreamReader::StartElement:
            if(srr.name().toString() == "Relationship")
            {
                QString f, s;
                for(int i = 0; i < srr.attributes().count(); i++)
                {
                    if( srr.attributes().at(i).name() == "Id" )
                        s = srr.attributes().at(i).value().toString();
                    if( srr.attributes().at(i).name() == "Target" )
                        f = srr.attributes().at(i).value().toString();
                }
                if(f.indexOf("cover") != -1)
                {
                    book->append("<p align=\"center\"><img src=\""
                                 + filerels + "/" + f
                                 + "\" alt=\"рисунок\"" + "/></p>");
                }
                else
                    img_fb3.insert(s, f);
                //qDebug() << f;
            }
            break;
        default: ;
        }
    }
    fr.close();
    break;
}

Außerdem gibt es einige Tags, deren Zweck mir nicht ganz klar ist: , .

Zip-Archiv öffnen

Ursprünglich hatte ich geplant, das 7z-Programm zum Entpacken zu verwenden. Aber diese Option verschwand, als ich herausfand, dass Sie das Entpacken von Dateien mithilfe der zlib-Bibliothek und Schnittstellen aus den Bibliotheken zipreader_p.h, zipwriter_p.h und zip.cpp implementieren können, die Sie [herunterladen] können (https://github.com/radekp /qt/tree/master/src/gui/text) zusammen mit anderen Qt-Quellen. Am Ende fand ich heraus, dass diese Bibliotheken auch in den Qt Redistributables (gui-private module) enthalten sind. Übrigens hat jedes Hauptmodul ein solches privates Zwillingsmodul. Und wie die Warnung in jeder der privaten Header-Dateien sagt:
(Diese Datei ist nicht Teil der Qt-API. Sie existiert lediglich als Implementierungsdetail. Diese Header-Datei kann sich von Version zu Version ohne Vorankündigung ändern oder sogar entfernt werden).
Die Funktion UnZip(QString name, QString path) fügt also den Inhalt des Namensarchivs in den Pfadordner ein. Als temporären Speicher schlage ich vor, den Ordner "dmreader" zu verwenden, der im Verzeichnis zum Speichern temporärer Dateien QStandardPaths::standardLocations(QStandardPaths::TempLocation).at(0) erstellt wurde.
Implementierung des Entpackens von Archiven

bool openerTextFiles::UnZip(QString zfile, QString path)
{
    QZipReader cZip(zfile);
    QDir dir(path);
    if(!dir.exists())
        dir.mkpath( path );

    //bool b = cZip.extractAll( path );
    bool b = extractFiles( cZip , path );
    cZip.close();
    return b;
}

Wenn wir es mit einem Zip-Archiv zu tun hätten, würde es ausreichen, die Funktion extractAll(QString path) der Klasse QZipReader zu verwenden. Das fb3-Archiv hat jedoch eine Funktion, auf die ich hier nicht näher eingehen werde. Ich habe diesen Algorithmus auf meinem Knie in der Funktion extractFiles (QZipReader zip, QString path) hinzugefügt.

bool openerTextFiles::extractFiles(const QZipReader &zip, const QString &destinationDir)
{
    QDir baseDir(destinationDir);
    QVector<QZipReader::FileInfo> allFiles = zip.fileInfoList();
    // create directories first
    foreach (QZipReader::FileInfo fi, allFiles) {
        const QString absPath = destinationDir + QDir::separator() + fi.filePath;
        if (fi.isDir) {
            if (!baseDir.mkpath(absPath))
                return false;
            if (!QFile::setPermissions(absPath, fi.permissions))
                return false;
        }
    }
    //  ------------------------
    foreach (QZipReader::FileInfo fi, allFiles) {
        const QString absPath = destinationDir + "/" + fi.filePath;
        QString d; // для fb3
        if(absPath.indexOf("/") != -1)
        {
            d = absPath.left(absPath.lastIndexOf("/"));
            QDir dir(d);
            if(!dir.exists()){
                dir.mkdir(dir.path());
            }
        }
    }
    foreach (QZipReader::FileInfo fi, allFiles) {
        const QString absPath = destinationDir + "/" + fi.filePath;
        if(absPath.endsWith("/"))
        {
            if( !baseDir.exists(fi.filePath) )
            {
                if (!baseDir.mkdir(fi.filePath))
                    return false;
                if (!QFile::setPermissions(absPath, fi.permissions))
                    return false;
            }
        }
        else
        {
            QString d; // для fb3
            if(absPath.indexOf("/") != -1)
            {
                d = absPath.left(absPath.lastIndexOf("/"));
                QDir dir(d);
                if(!dir.exists()){
                    dir.mkdir(dir.path());
                }
            }
            QFile f(absPath);
            if (!f.open(QIODevice::WriteOnly))
                return false;
            f.write(zip.fileData(fi.filePath));
            f.setPermissions(fi.permissions);
            f.close();
        }
    }
    return true;
    //  ------------------------
    // set up symlinks
    foreach (QZipReader::FileInfo fi, allFiles) {
        const QString absPath = destinationDir + QDir::separator() + fi.filePath;
        if (fi.isSymLink) {
            QString destination = QFile::decodeName(zip.fileData(fi.filePath));
            if (destination.isEmpty())
                return false;
            QFileInfo linkFi(absPath);
            if (!QFile::exists(linkFi.absolutePath()))
                QDir::root().mkpath(linkFi.absolutePath());
            if (!QFile::link(destination, absPath))
                return false;
        }
    }
}

Der Quellcode des Programms kann hier heruntergeladen werden.

Fazit

Das geschriebene Programm erhebt keinen Anspruch auf volle Funktionsfähigkeit beim Lesen von fb3-Dateien. Aber um den Text zu öffnen, anzuzeigen und in html zu speichern, das in einer Vielzahl von Editoren verarbeitet werden kann, ist es großartig. Viel Spaß beim Lesen.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Evgenii Legotckoi
  • 20. Mai 2019 15:20

Добрый день!

Вы не думали разместить репозиторий проекта на GitHub?

Дмитрий
  • 21. Mai 2019 16:10

Приветствую!

Я думаю дойдёт и до этого, но пока изучать его у меня нет желания.

A
  • 19. Oktober 2024 08:19

Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
A
ALO1ZE19. Oktober 2024 08:19
Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken