Russian Qt Forum

Qt => Вопросы новичков => Тема начата: folax от Июнь 08, 2015, 14:57



Название: Копирование через QFileSystemModel dropmimedata
Отправлено: folax от Июнь 08, 2015, 14:57
Добрый день. Подскажите пожалуйста, реализовал просмотр файловой системы через QTableView и QFileSystemModel, для копирования и вставки элементов использую 

Код:
QApplication::clipboard()->setMimeData
и
Код:
fileModel->dropMimeData(QApplication::clipboard()->mimeData(), cutOrCopy, 0, 0, qobject_cast<QAbstractItemView *>(focus)->rootIndex());

Вопрос состоит в следующем. При копировании больших файлов, программа зависает до тех пор пока не произойдёт копирование. Как реализовать правильно процесс копирования этого большого файла (в будущем группу файлов) и видеть процесс копирования чтоб потом например его передавать в QProgressBar, и как сделать чтобы программа не зависала.

На второй вопрос есть где то мысль что нужно использовать потоки, но как быть с большим файлов и прогрессом копирования его. Спасибо.


Название: Re: Копирование через QFileSystemModel dropmimedata
Отправлено: __Heaven__ от Июнь 08, 2015, 15:46
Да, нужны потоки. Для больших файлов нужен свой класс с двумя QFile. Один для чтения, другой для записи. Данные копировать порциями.


Название: Re: Копирование через QFileSystemModel dropmimedata
Отправлено: folax от Июнь 10, 2015, 14:52
Хотел бы спросить совета. Я пока что до потока не дошёл. Сделал так для проверки. Создал класс как вы и советовали с двумя QFile, решил попробовать делать emit для QProgressBar, я разделил файл который копируется на 100 частей, и делаю его копирование по частям и делаю инкремент каждый раз для QProgressBar. Я думал программа не должна виснуть раз создаётся сигнал, по идее должен же передаваться статус из класса в виджет.  А получается класс отработал и сразу показует 100% готовности. Подскажите что делать, реализовать эту процедуру через потоки ? Код ниже, подставляется файл для копирования и указывается путь куда копируется.

Код:
void FilesCopy::loadFile(QString fPath, QString fDest)
{
    if (fPath.isEmpty())
        return;

    //input file;
    QFile inputFile(fPath);
    if (!inputFile.open(QFile::ReadOnly))
    {
        qDebug()<<"Could not open the input file";
    }

    //output file;
    QFileInfo fileInfo(inputFile.fileName());
    QString destination = fDest + (fileInfo.fileName());
    qDebug()<<destination;
    QFile outputFile(destination);
    if (!outputFile.open(QFile::WriteOnly))
    {
        qDebug()<<"Could not open the output file";
    }
    //div file size to 100;
    int copyPart = inputFile.size() / 100;
    int status = 0;

    //if file size bigger then 100mb;
    if (inputFile.size() > 104857600)
    {
        QByteArray dataFromFile;
        qint64 tmp = 0;

        for (int i = 0; i < 100; ++i)
        {
            qDebug()<<i<<" i = "<<inputFile.pos()<<"\n";
            inputFile.seek(tmp);
            tmp += copyPart;
            if (i == 100)
            {
                dataFromFile = inputFile.readAll();
            }
            else
            {
                dataFromFile = inputFile.read(copyPart);
            }
            outputFile.write(dataFromFile);
            dataFromFile.clear();
            ++status;
        }
    }
    else
    {
        QFile::copy(fPath, destination);
        status = 100;
    }
    qDebug()<<outputFile.size()<< "= output file\n";
    qDebug()<<inputFile.size()<<" = input file\n";
    qDebug()<<status;

    outputFile.flush();
    outputFile.close();
    emit copyStatus(status);
}

изображение
(http://i.piccy.info/i9/3515b2ac343fb2cbd354585b035672ce/1434009523/35386/918803/copyfiles_500.jpg) (http://piccy.info/view3/8333077/34154b6f8088298c1cc2be0f063d6c2b/)(http://i.piccy.info/a3/2015-06-11-07-58/i9-8333077/449x372-r/i.gif) (http://i.piccy.info/a3c/2015-06-11-07-58/i9-8333077/449x372-r)

код
https://drive.google.com/file/d/0B_J3Y23JUfbmMHdrdGF2OXVJSU0/view?usp=sharing (https://drive.google.com/file/d/0B_J3Y23JUfbmMHdrdGF2OXVJSU0/view?usp=sharing)


Название: Re: Копирование через QFileSystemModel dropmimedata
Отправлено: Пантер от Июнь 10, 2015, 14:56
Нужно копирование вынести в поток.


Название: Re: Копирование через QFileSystemModel dropmimedata
Отправлено: Igors от Июнь 10, 2015, 15:23
Я думал программа не должна виснуть раз создаётся сигнал, по идее должен же передаваться статус из класса в виджет.  А получается класс отработал и сразу показует 100% готовности.
В приведенном коде прогресс обновляется 1 раз (emit в конце) - ну он один раз и покажет. Вставьте эту строку (emit copyStatis) в тело цикла, ++status само по себе UI не обновит


Название: Re: Копирование через QFileSystemModel dropmimedata
Отправлено: folax от Июнь 11, 2015, 14:23
Спасибо всем за помощь, получилось, так как и советовали вынес процесс копирования в отдельный слот, в вызывающем классе создал очередь, подключил к слоту очереди процесс копирования, потом запустил саму очередь.
Код:

Код:
void FilesCopy::process()
{
    //div file size to 100;
    int copyPart = inputFile.size() / 100;
    int status = 0;

    //if file size bigger then 100mb;
    if (inputFile.size() > 104857600)
    {
        QByteArray dataFromFile;
        qint64 span = 0;

        for (int i = 0; i < 100; ++i)
        {
            qDebug()<<i<<" i = "<<inputFile.pos()<<"\n";
            inputFile.seek(span);
            span += copyPart;
            if (i == 100)
            {
                dataFromFile = inputFile.readAll();
            }
            else
            {
                dataFromFile = inputFile.read(copyPart);
            }
            outputFile.write(dataFromFile);
            dataFromFile.clear();
            ++status;
            emit copyStatus(status);
        }
    }
    else
    {
        QFile::copy(filePatch, fileDestination);
        status = 100;
    }
    outputFile.flush();
    outputFile.close();
}

С сам поток:
 
Код:
thread = new QThread;

    fc = new FilesCopy();
    connect(fc, SIGNAL(copyStatus(int)), ui->progressBar, SLOT(setValue(int)));
    connect(thread, SIGNAL(started()), fc, SLOT(process()));
    fc->moveToThread(thread);

void Widget::on_copyBtn_clicked()
{
    fc->loadFile(file_Source, file_Destionation);
    thread->start();
}

В перспективе сейчас сделать, так чтобы можно было передавать несколько файлов а не одиночные.