Trabajador sin locking: copia de archivo de interrupción

Estoy lidiando con archivos muy grandes, que superan los cientos de GB de tamaño. El usuario debe poder mover estos archivos entre discos y se encuentra en un sistema restringido sin un administrador de archivos predeterminado. Es posible que el Usuario se dé cuenta de que cometió un error y cancele la operación, y por lo que yo sé, el Usuario deberá esperar a que se complete la operación actual de copia o cambio de nombre. Esto puede hacer que se sientan frustrados mientras esperan potencialmente minutos, solo para ver que sus muchos archivos GB todavía se copian. En el caso de Copiar, podría eliminar el segundo archivo, pero en el caso de cambiar el nombre, que estoy usando para mover archivos, tendría que repetir la operación al revés para deshacerlo, y eso simplemente no es aceptable.

¿Hay alguna manera de interrumpir copy () y rename () que no estoy viendo en la documentación de QFile, o tendré que armar mi propia clase para gestionar la copia y el cambio de nombre?

No creo que el tamaño del archivo tenga algún efecto sobre el tiempo que tardará un cambio de nombre.

Para la copia, Qt no ofrece nada integrado, tiene que implementarlo usted mismo. La clave que tenemos aquí es que tendrá que encontrar la manera de sondear una cancelación de copia continuamente. Esto significa que no puede bloquear el hilo principal para poder procesar eventos.

Ya sea que busque un hilo adicional para que el hilo principal responda o decida utilizar el hilo principal, en ambos casos deberá implementar una copia “fragmentada”, un fragmento a la vez, utilizando un búfer, hasta que el archivo sea copiado o copiado se cancela. Necesita esto para poder procesar eventos de usuario y seguir el progreso de copiado.

Sugiero que implemente una clase de asistente de copiado derivado de QObject que rastrea el nombre de archivo, el tamaño total, el tamaño del búfer, el progreso y la limpieza al cancelar. Entonces es una cuestión de elección si lo usará en el hilo principal o en un hilo dedicado.

EDIT: lo encontré, pero es mejor que lo revises dos veces, ya que se hizo como un ejemplo y no se ha probado a fondo:

 class CopyHelper : public QObject { Q_OBJECT Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged) public: CopyHelper(QString sPath, QString dPath, quint64 bSize = 1024 * 1024) : isCancelled(false), bufferSize(bSize), prog(0.0), source(sPath), destination(dPath), position(0) { } ~CopyHelper() { free(buff); } qreal progress() const { return prog; } void setProgress(qreal p) { if (p != prog) { prog = p; emit progressChanged(); } } public slots: void begin() { if (!source.open(QIODevice::ReadOnly)) { qDebug() << "could not open source, aborting"; emit done(); return; } fileSize = source.size(); if (!destination.open(QIODevice::WriteOnly)) { qDebug() << "could not open destination, aborting"; // maybe check for overwriting and ask to proceed emit done(); return; } if (!destination.resize(fileSize)) { qDebug() << "could not resize, aborting"; emit done(); return; } buff = (char*)malloc(bufferSize); if (!buff) { qDebug() << "could not allocate buffer, aborting"; emit done(); return; } QMetaObject::invokeMethod(this, "step", Qt::QueuedConnection); //timer.start(); } void step() { if (!isCancelled) { if (position < fileSize) { quint64 chunk = fileSize - position; quint64 l = chunk > bufferSize ? bufferSize : chunk; source.read(buff, l); destination.write(buff, l); position += l; source.seek(position); destination.seek(position); setProgress((qreal)position / fileSize); //std::this_thread::sleep_for(std::chrono::milliseconds(100)); // for testing QMetaObject::invokeMethod(this, "step", Qt::QueuedConnection); } else { //qDebug() << timer.elapsed(); emit done(); return; } } else { if (!destination.remove()) qDebug() << "delete failed"; emit done(); } } void cancel() { isCancelled = true; } signals: void progressChanged(); void done(); private: bool isCancelled; quint64 bufferSize; qreal prog; QFile source, destination; quint64 fileSize, position; char * buff; //QElapsedTimer timer; }; 

La señal done() se utiliza para deleteLater() el cuadro de diálogo Copiar ayuda / Cerrar copia o lo que sea. Puede habilitar el temporizador transcurrido y usarlo para implementar también una propiedad de tiempo transcurrido y el tiempo estimado. La pausa es otra característica posible de implementar. El uso de QMetaObject::invokeMethod() permite que el bucle de eventos procese periódicamente los eventos del usuario para que pueda cancelar y actualizar el progreso, que va de 0 a 1. También puede modificarlo fácilmente para mover archivos.

No creo que la función que estás buscando exista.

Lo que puede hacer es usar la función copy (), crear un nuevo archivo y leer gradualmente (qint64 maxSize) a un QByteArray del archivo anterior y escribir (const QByteArray & byteArray) en el nuevo archivo. De esta forma puede controlar el flujo usted mismo, solo verifique si el usuario no ha presionado cancelar entre cada lectura / escritura.