OpenHarmony—文件管理系列之單個文件的復制

前言
誠然,對于單個文件的復制我們可以直接調用文件管理的接口去實現,使用fileio.copyFile輸入待復制文件的路徑與目標文件夾的路徑就可以實現對單個文件的復制,但是如果直接使用這個方法的話,我們如何獲取到單個文件復制時的進度呢?
整體思路
我們可以把整個復制單個文件的過程比作一個復制一桶水的過程:
我們現在的任務是復制一桶水,且需要獲取到復制一桶水的進度。首先,我們首先會第一眼看到,這是一個什么顏色的水桶,紅色的還是黃色的?然后我們需要打開水桶的蓋子,看里面的水內容是什么,接著我們會把我們看見的內容記在我們的腦海里。這時候我們再去拿一個一模一樣的空桶,往里面加入剛才記在我們腦海中的水。
同理:我們首先接受到的應該是我們需要復制文件的絕對路徑,這樣我們就能通過裁剪字符串的方式,獲取到這個文件的格式:是txt,是ppt還是png格式呢?文件格式對應著上述例子的水桶的顏色。然后,我們需要調用fileio.openSync打開需要復制的文件,先創建一個緩存區new ArrayBuffer作為讀取內容后存放的位置,再通過調用fileio.readSync將我們讀取到的內容存放在我們的腦海(緩存區)里。然后,我們會創建一個新的空的,與被復制文件相同格式的文件,同樣,我們需要打開這個空文件之后,調用fileio.writeSync來將緩存區的內容寫入到這個文件中。
希望這樣的解釋與類比可以讓讀者對單個文件的復制有一個比價深刻的印象。
上述的流程是整體的復制文件的流程,那我們該如何在這個過程中獲取到文件的進度呢?在這里我選擇的是通過控制每次讀取的內容,來控制寫入的速度。假設一個要被復制的文件大小為1G,每次我們都只讀取1M長度的數據流,那么我們每次都只寫入這1M長度的數據流,我們就需要循環寫入1024次,在此期間不停的獲取此時新文件的大小與被復制文件的大小的比例,這樣一來,進度的數據就實現了。
代碼實現
//單個文件的復制
duplicate1(path) {
let dir = fileio.openSync(path)
let index = path.lastIndexOf(".")
let ind = path.lastIndexOf("/")
let item = {
size: fileio.statSync(path).size,
path: path,
fileName: path.slice(ind+1, index),
fileType: path.slice(index + 1)
}
let currentPath = path.slice(0, ind)
let duplicationSize = item.size
let duplicatedSize = 0
let fd = fileio.openSync(item.path, 0o100 | 0o2, 0o666)
//經過實驗,在使用fileio.readSync這個api之前,一定要先寫入..算是一個小bug了
let num = fileio.writeSync(fd, "");
fileio.closeSync(fd);
let i = 0
let processor = 0
let timer = setInterval(() => {
//我們需要對邊界值進行一定的處理,以防我們復制文件的大小與我們設定的讀取的長度成整數倍
if (i > (Math.floor((item.size - 1) / READ_LENGTH) + 1)) {
clearInterval(timer)
} else {
//打開被復制的文件
let fd2 = fileio.openSync(item.path, 0o100 | 0o2, 0o666)
//創建緩存區
let buf = new ArrayBuffer(READ_LENGTH)
//設定讀取的長度,讀取的位置
let num1 = fileio.readSync(fd2, buf, { position: READ_LENGTH * i, length: READ_LENGTH })
//關閉被復制的文件
fileio.closeSync(fd2);
//創建與文件格式相同的空文件
let copypath = currentPath + '/' + item.fileName + '*.' + item.fileType;
//打開新文件
let copyfd = fileio.openSync(copypath, 0o100 | 0o2, 0o666)
//寫入,position與讀取被復制文件的時的位置相同,length的長度應該與讀取被復制文件時的長度相同
fileio.writeSync(copyfd, buf, { position: i * READ_LENGTH, length: num1 });
//關閉新文件
fileio.closeSync(copyfd)
//獲取當前新文件的大小
duplicatedSize = fileio.statSync(copypath).size
let processValue = duplicatedSize
//新文件的大小除以被復制文件的大小即為進度
processor = (processValue / duplicationSize) * 100
log("this.duplicatedSize:", duplicatedSize)
this.getProcessor(processor)
i += 1
}
}, 1)
}
除了通過控制讀取的長度控制寫入的長度來計算進度以外,我們還有一種獲取進度的方式:一次性讀取全部的內容,但是分段寫入。這種方法我們需要先將緩存區存儲的內容轉為數組的格式,將該數組分為若干等份的小數組,再將每一份小數組轉換回緩存區的格式,才可以寫入到新的空文件當中去。這種方法如果用于小文件的復制可能看不出效率的區別,但是如果是大文件復制的情況效率就會很低,所以我們不推薦使用。




























