深度文件管理器文件拷貝原理

看了深度文件管理器 filejob 這個模塊之後,對它的拷貝文件原理也瞭解了一下。

大概是這麼一個流程:

  • 傳入兩個類型爲 QString 的變量:源文件地址(fromPath)、目標目錄(tarDir)
  • 求出目標文件完整地址:目標目錄 + 源文件名,targetPath = tarDir + fromPath.fileName()
  • 定義了寫入數據塊大小:DATA_BLOCK_SIZE 爲 65536
  • 創建兩個 QFile 對象(源文件地址與目標文件地址)
  • 調用 QFile::open() 方法,源文件打開模式爲只讀(ReadOnly),目標文件打開模式爲只寫(WriteOnly)
  • 調用 QIODevice::read() 方法,每次讀取一塊字節數據,會返回讀取的字節數(如果爲0則代表拷貝成功,-1 說明失敗)
  • 調用 QIODevice::write() 循環寫入一個數據塊,也會返回寫入的字節數,如果爲0就會停止循環,說明文件拷貝成功

使用 Qt 讀寫類 QFile 來進行文件讀寫操作,都會調用到系統 open、read、write...

計算拷貝文件百分比進度也很簡單,在寫入過程中把已寫入字節數存儲,已寫入字節數 / 總字節數 * 100.0 就是當前拷貝文件的進度,計算的公式也就是:

percent = bytesCopied / TotalByte * 100.0

拷貝文件簡單實現

#include <QFile>
#include <QFileInfo>

#define DATA_BLOCK_SIZE 1000

bool copyFile(const QString &fromPath, const QString &targetDir)
{
    QFileInfo fromFileInfo(fromPath);
    QString targetPath = QString("%1/%2").arg(targetDir).arg(fromFileInfo.fileName());

    QFile fromFile(fromPath);
    QFile targetFile(targetPath);
    char dataBuffer[DATA_BLOCK_SIZE];

    quint64 bytesCopied = 0;
    quint64 totalByte = fromFile.size();

    // 如果源文件不可讀直接返回 false
    if (!fromFile.open(QIODevice::ReadOnly)) {
        return false;
    }

    // 如果目標文件不可寫直接返回 false
    if (!targetFile.open(QIODevice::WriteOnly)) {
        return false;
    }

    while (true) {
        // 讀取一段數據塊
        qint64 inBytes = fromFile.read(dataBuffer, DATA_BLOCK_SIZE);

        if (inBytes == 0) {
            fromFile.close();
            targetFile.close();

            // 寫入完成後設置目標文件的權限
            // 保持目標文件與源文件權限是一致的
            targetFile.setPermissions(fromFile.permissions());

            return true;
        } else if (inBytes == -1) {
            fromFile.close();
            targetFile.close();
            return false;
        }

        qint64 availableBytes = inBytes;

        while (true) {
            // 寫入一段數據塊
            qint64 writtenBytes = targetFile.write(dataBuffer, availableBytes);
            availableBytes = availableBytes - writtenBytes;

            // 一段數據塊寫入完成後終止循環
            if (writtenBytes == 0 && availableBytes == 0){
                break;
            }
        }

        // 輸出百分比進度
        bytesCopied += inBytes;
        qDebug() << bytesCopied / totalByte * 100.0;
    }

    return false;
}

拷貝文件夾

拷貝文件夾通過遍歷文件夾每個文件然後調用 copyFile() 進行拷貝操作。

遍歷目錄拷貝文件之前根據 inode 對所有文件進行一次排序,然後再進行拷貝操作。

Linux 零拷貝技術

Linux 中提供類似的系統調用主要有 sendfile()、mmap() 和splice()

參考:Linux 中的零拷貝技術 splice

最後

具體代碼實現請看:filejob.cpp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章