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