怎么在QML应用中读写文件

如何在QML应用中读写文件

我们知道,在QML应用中,有时我们需要来读写一些文件,但是在我们的QML语言中并没有相应的API接口来供我们做(虽然有API接口来存储设置文件等)。那么我们怎么来做这个事情呢?我们可以通过Qt C++的方法来实现这个功能。


1)创建一个简单的模版应用


我们使用Ubuntu SDK的模版来创建一个最简单的应用:

怎么在QML应用中读写文件  怎么在QML应用中读写文件

怎么在QML应用中读写文件 怎么在QML应用中读写文件

我们选择“QML App with C++ plugin”模版来做我们的应用。


2)添加文件读写的文件到项目中

我们添加如下的C++ "FileIO类到我们的backend plugin中:

#ifndef FILEIO_H
#define FILEIO_H

#include <QObject>
#include <QTextCodec>
#include <QDebug>

class FileIO : public QObject
{
    Q_OBJECT

public:
    Q_PROPERTY(QString source
               READ source
               WRITE setSource
               NOTIFY sourceChanged)
    explicit FileIO(QObject *parent = 0);

    Q_INVOKABLE QString read();
    Q_INVOKABLE bool write(const QString& data);

    QString source() { return mSource; };

public slots:
    void setSource(const QString& source) { mSource = source; };

signals:
    void sourceChanged(const QString& source);
    void error(const QString& msg);

private:
    QString getenv(const QString envVarName) const;

private:
    QString mSource;
    QString datapath;
};

inline QString GBK2UTF8(const QString &inStr)
{
    QList<QByteArray> codecs = QTextCodec::availableCodecs();

    for ( int i = 0; i < codecs.length(); i ++ ) {
//        qDebug() << "codec: " + QTextCodec::codecForMib(1015)->toUnicode(codecs.at(i));
        qDebug() << "codec: " << QString::fromLocal8Bit(codecs.at(i));
    }

    QTextCodec *gbk = QTextCodec::codecForName("GBK");

    QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
//    QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");

    QString g2u = gbk->toUnicode(gbk->fromUnicode(inStr)); // gbk  convert utf8
    return g2u;
}

#endif // FILEIO_H

#include "fileio.h"
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QFileInfo>
#include <QTextCodec>

FileIO::FileIO(QObject *parent) : QObject(parent)
{
    datapath = getenv("TMPDIR")  + "/";
    qDebug() << "datapath: " + datapath;
}

QString FileIO::read()
{    
    qDebug() << "reading ....!";

    if (mSource.isEmpty()){
        emit error("source is empty");
        return QString();
    }

    QFile file(datapath + mSource);
    QFileInfo fileInfo(file.fileName());
    qDebug() << "file path: " << fileInfo.absoluteFilePath();

    QString fileContent;
    if ( file.open(QIODevice::ReadOnly) ) {
        QString line;

        QTextCodec *gbk = QTextCodec::codecForName("GBK");
        QTextStream t( &file );
        t.setCodec(gbk);

        do {
            line = t.readLine();
            fileContent += line;
        } while (!line.isNull());

        file.close();
        return fileContent;
    } else {
        emit error("Unable to open the file");
        return QString();
    }
}

bool FileIO::write(const QString& data)
{
    qDebug() << "writing.....";

    if (mSource.isEmpty())
        return false;

    QFile file(datapath + mSource);
    QFileInfo fileInfo(file.fileName());
    qDebug() << "file path: " << fileInfo.absoluteFilePath();
    if (!file.open(QFile::WriteOnly | QFile::Truncate))
        return false;

    QTextStream out(&file);
    out << data;

    file.close();

    return true;
}

QString FileIO::getenv(const QString envVarName) const
{
    QByteArray result = qgetenv(envVarName.toStdString().c_str());
    QString output = QString::fromLocal8Bit(result);
    qDebug() << envVarName << " value is: "  << output;
    return output;
}

这个类是可以向我们指定的文件地址读写文件。注意,我们使用了getenv来获取可以读写的文件目录。Ubuntu应用不是可以打开任何一个文件目录进行读写的。具体可以参考文章“Ubuntu OS应用Runtime Enviroment”来得到更多的了解。在这个例程中,我们指定了文件的编码方式为GBK。你们可以不指定或指定为你所需要的编码方式。

在backend的CMakeLists.txt中加入:

    modules/ReadFileQML/fileio.cpp

同时在backend.cpp中加入:

void BackendPlugin::registerTypes(const char *uri)
{
    Q_ASSERT(uri == QLatin1String("ReadFileQML"));

    qmlRegisterType<MyType>(uri, 1, 0, "MyType");
    qmlRegisterType<FileIO>(uri, 1, 0, "FileIO"); // added line
}

这样就完成了我们的plugin的设计。


3)在应用中调用

为了测试我们的plugin,我们修改我们的readfileqml.qml文件如下:

import QtQuick 2.0
import Ubuntu.Components 1.1
import ReadFileQML 1.0

/*!
    \brief MainView with Tabs element.
           First Tab has a single Label and
           second Tab has a single ToolbarAction.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "readfileqml.liu-xiao-guo"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    // Removes the old toolbar and enables new features of the new header.
    useDeprecatedToolbar: false

    width: units.gu(60)
    height: units.gu(76)

    Page {
        title: i18n.tr("Read File QML")

        Text {
            id: myText
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: button.top

            wrapMode: Text.Wrap
        }

        Button {
            id: button
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom:parent.bottom
            height: units.gu(5)

            text: "Reload file"

            onClicked: {
                console.log("button is clicked!");
                //reload the file
                myText.text =  myFile.read();
            }
        }

        FileIO {
            id: myFile
            source: "good.txt"
            onError: console.log(msg)
        }

        Component.onCompleted: {
            console.log( "WRITE: "+ myFile.write("this is really cool!"));
            console.log("source: " + myFile.source );
            myText.text =  myFile.read();
        }
    }
}

这里,我们定义了:


        FileIO {
            id: myFile
            source: "good.txt"
            onError: console.log(msg)
        }

我们可以通过它向我们的文件“good.txt”来读写文件了。注意good.txt文件的地址。

怎么在QML应用中读写文件

所有的源码在地址: git clone https://gitcafe.com/ubuntu/readfileqml.git