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