2013-12-17 131 views
0

我有這個程序,我想用一個循環將多個文件的數據發送到一個文件中,但這似乎不能正常工作。Qt無法將多個文件數據附加到一個

void MainWindow::on_pushButton_clicked() 
{ 
    FILE *fp1,*fp2; 
    char ch; 
    QString str="test"+i+".txt"; 
    QString qString1 =str.toUtf8(); 
    QByteArray byteArray = qString1.toUtf8(); 

    const char* fname1 = byteArray.constData(); 
    if(QFile::exists("test0.txt")) 
    fp1=fopen(fname1,"r"); 
    fp2=fopen("CheckoutReport.txt","a"); 
    do 
    { 
     ch=fgetc(fp1); 
     fputc(ch,fp2); 
    } 
    while(ch!=EOF); 
    fcloseall(); 
} 
+0

什麼是你所面臨的具體問題? – Hariprasad

+1

'QString qString1 = str.toUtf8()'沒有任何意義。您將'str'轉換爲'QByteArray',其中包含字符串的UTF-8表示形式,並使用使用Latin1編碼的默認構造函數立即將其轉換回QString。你應該使用'QByteArray byteArray = str.toLocal8Bit();'而不是如果你想在本地函數中使用這個字符串。你應該使用'QFile'而不是原生函數。 –

+0

這取決於@PavelStrakhov:在Qt5中,QString類存儲對應於Unicode 4.0(http://qt-project.org/doc/qt-5.0/qtcore/qstring.html#details)的16位QChar,而非Latin-1這是Qt4的默認設置。也就是說,使用toUtf8()並直接將結果存儲在QString中仍然沒有任何意義... – Antwane

回答

1

有幾個問題:

  1. 你有兩個C++ Qt中,用QFile,不要使用明火的C文件!

  2. qString1是窮人的str副本,所以有什麼意義呢?

  3. 逐個字符地複製文件表現相當差。

  4. 一般來說,您不想在執行文件操作時阻止您的GUI。他們應該在一個單獨的線程中完成。

下面是它如何完成的一個例子。我努力充分利用Qt提供的功能,同時保持QWidget爲基礎。這是一個自包含的單文件示例,只需將其作爲單獨文件添加到Qt Creator中的qt項目項目中,然後構建並運行即可。請記住,此代碼將在其當前工作目錄中打開文件!

根據代碼複雜度使用另一個線程的成本實際上是6行。如果您不關心使用單獨的文件訪問線程,並且您的用戶界面被網絡上可能較慢的文件阻塞等情況良好,則可以刪除以下6行,而無需對代碼進行任何其他更改。這就是Qt的美麗。

QThread * m_thread; 
w->moveToThread(m_thread); 
m_thread(new QThread(this)), 
m_thread->start(); 
m_thread->exit(); 
m_thread->wait(); 

不到位線程,你也可以用一個簡單的w->joinFiles()更換QMetaObject::invokeMethod(w, "joinFiles");。使用invokeMethod而不是直接調用的原因是調用對象正在運行的線程中的插槽。 invokeMethod將在幕後向工作者對象發佈QMetaCallEvent。該事件將被線程中運行的事件循環拾取,並且將導致調用工作人員的joinFiles插槽,該插槽在正確線程 - worker->thread()內執行。

請注意,我不是從QThread派生的,並且只有一個線程用於所有文件操作。如果您的出發點是在GUI線程中完成所有文件訪問,那麼這非常合適。這樣就有兩個線程:一個只做GUI,另一個只做序列化文件訪問。

screenshot

#include <QWidget> 
#include <QPushButton> 
#include <QPlainTextEdit> 
#include <QLineEdit> 
#include <QSpinBox> 
#include <QLabel> 
#include <QFormLayout> 
#include <QMetaObject> 
#include <QFile> 
#include <QDir> 
#include <QThread> 
#include <QApplication> 

class Worker : public QObject { 
    Q_OBJECT 
    Q_PROPERTY(int fileIndex READ fileIndex WRITE setFileIndex) 
    Q_PROPERTY(QString sourceFileName READ sourceFileName) 
    Q_PROPERTY(QString targetFileName READ targetFileName WRITE setTargetFileName) 
    int m_fileIndex; 
    QString m_targetFileName; 
public: 
    Worker(int fileIndex, QString targetFileName, QObject * parent = 0) : 
     QObject(parent), m_fileIndex(fileIndex), m_targetFileName(targetFileName) {} 
    explicit Worker(QObject * parent = 0) : QObject(parent), m_fileIndex(0) {} 
    Q_SIGNAL void filesJoined(bool OK); 
    Q_SLOT void joinFiles() { 
     QFile src(sourceFileName()); 
     QFile dst(m_targetFileName); 
     if (! src.open(QIODevice::ReadOnly) 
      || ! dst.open(QIODevice::Append)) 
     { 
      emit filesJoined(false); 
      return; 
     } 
     while (! src.atEnd()) { 
      dst.write(src.read(16384)); 
     } 
     emit filesJoined(true); 
    } 
    int fileIndex() const { return m_fileIndex; } 
    void setFileIndex(int i) { m_fileIndex = i; } 
    QString sourceFileName() const { return QString("test%1.txt").arg(m_fileIndex); } 
    QString targetFileName() const { return m_targetFileName; } 
    void setTargetFileName(const QString & n) { m_targetFileName = n; } 
}; 

class Window : public QWidget { 
    Q_OBJECT 
    QThread * m_thread; 
    QSpinBox * m_index; 
    QLineEdit * m_target; 
    QPlainTextEdit * m_log; 
    Q_SLOT void on_pushButton_clicked() { 
     Worker * w = new Worker; 
     w->setFileIndex(m_index->value()); 
     w->setTargetFileName(m_target->text()); 
     w->moveToThread(m_thread); 
     connect(w, SIGNAL(filesJoined(bool)), SLOT(onJoined(bool))); 
     QMetaObject::invokeMethod(w, "joinFiles"); 
    } 
    Q_SLOT void onJoined(bool ok) { 
     const Worker * w = qobject_cast<const Worker*>(sender()); 
     m_log->appendPlainText(QString("%1 %2 to %3") 
           .arg(ok ? "Successfully joined" : "Couldn't join") 
           .arg(w->sourceFileName()).arg(w->targetFileName())); 
     sender()->deleteLater(); 
    } 
public: 
    Window(QWidget * parent = 0) : 
     QWidget(parent), 
     m_thread(new QThread(this)), 
     m_index(new QSpinBox), 
     m_target(new QLineEdit), 
     m_log(new QPlainTextEdit) 
    { 
     QFormLayout * layout = new QFormLayout(this); 
     QPushButton * button = new QPushButton("Join Files"); 
     button->setObjectName("pushButton"); 
     layout->addRow("File Index", m_index); 
     layout->addRow("Append to File Name", m_target); 
     layout->addRow(button); 
     layout->addRow(m_log); 
     QMetaObject::connectSlotsByName(this); 
     m_thread->start(); 
     m_log->appendPlainText(QString("Current directory: %1").arg(QDir::currentPath())); 
    } 
    ~Window() { 
     m_thread->exit(); 
     m_thread->wait(); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    Window w; 
    w.show(); 
    return a.exec(); 
} 

#include "main.moc" 
+0

我不會說'fgetc'和'fputc'表現特別差。他們做內部緩衝,性能可能仍然是IO綁定,只是CPU負載增加。 – hyde

+1

@hyde:當然,但在這種情況下,他們僅僅是提問者的示範,不知道如何去做。它們不被設計使用,它們被偶然使用。我想強化這種做法的錯誤方式。 –