Russian Qt Forum
Ноябрь 22, 2024, 13:55 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Асинхронное копирование файлов вешает интерфейс  (Прочитано 8658 раз)
gladsky
Гость
« : Июнь 06, 2017, 13:03 »

Копирование большого файла в основном потоке приложения замораживает его интерфейс. Копирование в отдельном потоке не помогает. Подскажите, пожалуйста, почему интерфейс всё равно замерзает.
1. QtConcurrent::run. Начал с простого.
Выделяю копирование в отдельную функцию
Код:
void MainWindow::fileCopy(const QString &source, const QString &destination)
{
    QFile::copy(source, destination);
}
Само копирование:
Код:
QString source = "D:\Distrib\rlink20022014.rar";
QString destination = "\\Distrib\rlink20022014.rar"; //копирую в сетевую папку
QFuture<void> f1 = QtConcurrent::run(this, &MainWindow::fileCopy, source, destination);
При копировании большого файла интерфейс подвисает Грустный.

2. Ладно, идём дальше, беру QThread
Сначала делаю класс для копирования
filecopy.h
Код:
#ifndef FILECOPY_H
#define FILECOPY_H

#include <QObject>

class FileCopy : public QObject
{
    Q_OBJECT
public:
    FileCopy(const QStringList &files, const QString &path, QObject *parent = 0);
    ~FileCopy();

signals:
    void finished();

private slots:
    void process();

private:
    QStringList filesList;
    QString destination;
};

#endif // FILECOPY_H
filecopy.cpp
Код:
#include "filecopy.h"
#include <QFileInfo>
#include <QDir>
#include <QDebug>

FileCopy::FileCopy(const QStringList &files, const QString &path, QObject *parent)
     : QObject(parent)
{
    this->filesList = files;
    this->destination = path;
}

FileCopy::~FileCopy()
{

}

void FileCopy::process()
{
    foreach (QString file, filesList) {
        QFileInfo file_info(file);
        QString file_name = file_info.fileName();
        QString destination_file = destination + QDir::separator() + file_name;
        QFile::copy(file, destination_file);
        emit finished();
    }
}
Копируем:
Код:
        QStringList file_list;
        file_list << QDir::toNativeSeparators(url.toLocalFile());
        QString copyToAddress = "\\Distrib"
        QThread *thread = new QThread();
        FileCopy *fileCopy = new FileCopy(file_list, copyToAddress);
        fileCopy->moveToThread(thread);
        connect(thread, SIGNAL(started()), fileCopy, SLOT(process()));
        connect(fileCopy, SIGNAL(finished()), thread, SLOT(quit()));
        connect(fileCopy, SIGNAL(finished()), fileCopy, SLOT(deleteLater()));
        connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
        thread->start();
Не помогло  Злой

3. Может виновата QFile::copy? Переписываю класс filecopy, избавляюсь от QFile::copy
filecopy.h
Код:
#ifndef FILECOPY_H
#define FILECOPY_H

#include <QObject>

class FileCopy : public QObject
{
    Q_OBJECT
public:
    explicit FileCopy(const QStringList &files, const QString &path, QObject *parent = 0);
    ~FileCopy();

signals:
    void finished();

private slots:
    void process();

private:
    QStringList filesList;
    QString destination;
    quint64 bufferSize;
    char *buffer;
};

#endif // FILECOPY_H
filecopy.cpp
Код:
#include "filecopy.h"
#include <QFileInfo>
#include <QDir>
#include <QDebug>

FileCopy::FileCopy(const QStringList &files, const QString &path, QObject *parent)
     : filesList(files), destination(path), bufferSize(1024*512), QObject(parent)
{ }

FileCopy::~FileCopy()
{ }

void FileCopy::process()
{
    foreach (QString file, filesList) {

        QFileInfo fileInfo(file);
        QString sFileName = fileInfo.fileName();
        QString sDestinationFile = destination + QDir::separator() + sFileName;
        int i = 1;
        while (QFile::exists(sDestinationFile)) {
            sFileName = fileInfo.fileName() + "_" + QString::number(i)
                    + "." + fileInfo.suffix();
            sDestinationFile = destination + QDir::separator() + sFileName;
            i++;
        }

        QFile sourceFile(file);
        QFile destinationFile(sDestinationFile);
        if (!sourceFile.open(QIODevice::ReadOnly)) {
            emit finished();
            return;
        }
        if (!destinationFile.open(QIODevice::WriteOnly)) {
            emit finished();
            return;
        }
        quint64 fileSize = sourceFile.size();
        if (!destinationFile.resize(fileSize)) {
            emit finished();
            return;
        }
        buffer = (char*)malloc(bufferSize);
        if(!buffer) {
            emit finished();
            return;
        }

        quint64 position = 0;
        while (position < fileSize) {
            quint64 chunk = fileSize - position;
            quint64 i = chunk > bufferSize ? bufferSize : chunk;
            sourceFile.read(buffer, i);
            destinationFile.write(buffer, i);
            position += i;
            sourceFile.seek(position);
            destinationFile.seek(position);
        }

        emit finished();
    }
}
В основной программе копирование не изменилось. Чтобы не ходить далеко, привожу ещё раз
Код:
        QStringList file_list;
        file_list << QDir::toNativeSeparators(url.toLocalFile());
        QString copyToAddress = "\\Distrib"
        QThread *thread = new QThread();
        FileCopy *fileCopy = new FileCopy(file_list, copyToAddress);
        fileCopy->moveToThread(thread);
        connect(thread, SIGNAL(started()), fileCopy, SLOT(process()));
        connect(fileCopy, SIGNAL(finished()), thread, SLOT(quit()));
        connect(fileCopy, SIGNAL(finished()), fileCopy, SLOT(deleteLater()));
        connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
        thread->start();
Оно, конечно, теперь не виснет намертво на всё время копирования, но реагирует рывками - чем больше буффер, тем на большее время подвисает.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Июнь 06, 2017, 13:17 »

Странно, первый и второй способы корректны. А у тебя случаем не фризится вся система?
« Последнее редактирование: Июнь 06, 2017, 13:27 от Пантер » Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #2 : Июнь 06, 2017, 13:27 »

И еще вопрос - ты привел полный код или упростил его, удалив ненужное? Может, проблема в том коде, который ты не приводишь? Допустим, пытаешься GUI дергать внутри функции копирования.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
gladsky
Гость
« Ответ #3 : Июнь 06, 2017, 14:03 »

И еще вопрос - ты привел полный код или упростил его, удалив ненужное? Может, проблема в том коде, который ты не приводишь? Допустим, пытаешься GUI дергать внутри функции копирования.

Система не подвисает.
Код только копирует файлы, больше ничего ещё не навесил. Если заменить копирование на что-нибудь простое, типа как код ниже, то отрабатывает нормально, интерфейс не фризится.
Код:
for (int i = 0; i < 100; i++) {
    qDebug() << i;
    Sleep(uint(5000));
}
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Июнь 06, 2017, 14:14 »

А под замораживанием интерфейса ты что понимаешь?
Я писал свой ФМ, проблем таких не возникало.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #5 : Июнь 07, 2017, 08:18 »

сделал бы минимальный проект, можно было бы посмотреть
а разбираться в портянках кода и копипастить их откровенно лень
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #6 : Июнь 07, 2017, 13:21 »

+1, первый способ должен рабоатть. Случаем, футуру нигде не ждут?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.05 секунд. Запросов: 22.