여러 파일을 동시에 차단 한 다음 다른 위치로 복사하려고 시도했습니다.QFutureWatcher에서 QFuture 결과를 지우는 방법
원본 파일과 대상 파일을 동시에 차단해야합니다. 따라서 static QFile::copy()
기능을 사용할 수 없습니다.
QFile
으로 인해 파일을 보관하고 이동하려면 QSharedPointer<QFile>
을 사용할 수 없습니다. 복사 및 이동이 불가능합니다.
전체 작업을 완전히 수행하려면 QtConcurrent
프레임 워크를 사용하십시오. 즉 : QtConcurrent::mappedReduced
및 QFutureWatcher
.
using PFile = QSharedPointer<QFile>;
using PFileList = QList<PFile>;
template< typename Result, typename Functor >
struct FunctorWithResultType
: std::decay_t<Functor>
{
using result_type = Result;
FunctorWithResultType(Functor & functor)
: std::decay_t<Functor>{std::forward<Functor>(functor)}
{ ; }
};
template< typename Result, typename Functor >
FunctorWithResultType< Result, Functor >
addResultType(Functor && functor)
{
return {functor};
}
class Test
{
public :
QDir currentDirectory;
QFutureWatcher<PFileList> fileCopyFutureWatcher;
// ...
};
// ...
Test::Test()
{
auto onFilesCopied = [&]
{
PFileList copiedFiles = fileCopyFutureWatcher.result();
qCInfo(usbDevice) << "Files copy operation from drive finished.";
qCInfo(usbDevice) << copiedFiles.size();
for (PFile const & file : copiedFiles) {
//file->close(); // I want copiedFiles to be closed automatically at the end of current scope
}
};
connect(&fileCopyFutureWatcher, &fileCopyFutureWatcher.finished, onFilesCopied);
}
// ...
void Test::onDeviceAdded(QString deviceName)
{
qCInfo(usbDevice) << "USB device" << deviceName << "is added.";
if (!fileCopyFutureWatcher.isFinished()) {
return;
}
QDir sourceDirectory{deviceName};
if (!sourceDirectory.cd("dir")) {
qCInfo(usbDevice) << "Drive" << deviceName << "does not contain dir subdirectory.";
return;
}
auto destinationDirectory = currentDirectory;
if (!destinationDirectory.mkpath("fileCache")) {
qCCritical(usbDevice) << "Can't create fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
if (!destinationDirectory.cd("fileCache")) {
qCCritical(usbDevice) << "Can't change directory to fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
struct PFilePair
{
PFile source, destination;
};
auto openSourceAndDestinationFiles = [&, destinationDirectory] (QFileInfo const & fileInfo) -> PFilePair
{
auto source = PFile::create(fileInfo.absoluteFilePath());
QFile & sourceFile = *source;
if (!sourceFile.open(QFile::ReadOnly)) {
qCCritical(usbDevice) << "Can't open file" << sourceFile.fileName()
<< "to read:" << sourceFile.errorString();
return {};
}
auto destination = PFile::create(destinationDirectory.absoluteFilePath(fileInfo.fileName()));
QFile & destinationFile = *destination;;
if (!destinationFile.open(QFile::ReadWrite | QFile::Truncate)) {
qCCritical(usbDevice) << "Can't open file" << destinationFile.fileName()
<< "to write:" << destinationFile.errorString();
return {};
}
return {qMove(source), qMove(destination)};
};
auto copyFiles = [&] (PFileList & files, PFilePair const & filePair)
{
if (filePair.source.isNull() || filePair.destination.isNull()) {
return;
}
QFile & sourceFile = *filePair.source;
QFile & destinationFile = *filePair.destination;
qCInfo(usbDevice) << sourceFile.fileName() << "->" << destinationFile.fileName();
constexpr int size = (1 << 20); // 1MiB
QByteArray buffer{size, 0};
char * const data = buffer.data();
while (!sourceFile.atEnd()) {
auto bytesRead = sourceFile.read(data, size);
if (bytesRead < 0) {
qCCritical(usbDevice) << "Can't read file" << sourceFile.fileName()
<< ":" << sourceFile.errorString();
return;
}
auto bytesWritten = destinationFile.write(data, bytesRead);
while (bytesWritten < bytesRead) {
auto sizeWritten = destinationFile.write(data + bytesWritten, bytesRead - bytesWritten);
if (sizeWritten < 0) {
qCCritical(usbDevice) << "Can't write file" << destinationFile.fileName()
<< ":" << destinationFile.errorString();
return;
}
bytesWritten += sizeWritten;
}
Q_ASSERT(bytesWritten == bytesRead);
}
Q_ASSERT(sourceFile.size() == destinationFile.size());
destinationFile.flush();
files.append(filePair.destination);
};
QStringList nameFilters;
nameFilters << "file.dat";
// many other entries
auto entryInfoList = sourceDirectory.entryInfoList(nameFilters, (QDir::Readable | QDir::Files));
fileCopyFutureWatcher.setFuture(QtConcurrent::mappedReduced<PFileList>(qMove(entryInfoList), addResultType<PFilePair>(openSourceAndDestinationFiles), copyFiles));
}
// ...
QFutureWatcher::finished
이벤트의 결과를 읽은 후 모든 대상 파일은 여전히 열리고 내 응용 프로그램에 의해 차단. 그러므로 나는 QSharedPointer<QFile>
의 사본이 여전히 존재한다고 결론을 내릴 수 있습니다. 나는 그들이 QFutureWatcher
안에 QFuture
안에 떠나는 것을 의심한다. 가짜 QFuture
인스턴스로 QFutureWatcher::setFuture
을 호출하지 않고도 모든 파일을 지우려면 어떻게해야합니까 (즉, QFile::~QFile()
에서 모든 파일을 닫는 방법)?
이 결과를 복사하려면 QFuture
의 결과를 도용해야합니다.