前言
诚然,对于单个文件的复制我们可以直接调用文件管理的接口去实现,使用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)
}
除了通过控制读取的长度控制写入的长度来计算进度以外,我们还有一种获取进度的方式:一次性读取全部的内容,但是分段写入。这种方法我们需要先将缓存区存储的内容转为数组的格式,将该数组分为若干等份的小数组,再将每一份小数组转换回缓存区的格式,才可以写入到新的空文件当中去。这种方法如果用于小文件的复制可能看不出效率的区别,但是如果是大文件复制的情况效率就会很低,所以我们不推荐使用。