标签:来源 外部 blob span 生成 性能 理解 好的 data
1、buffer合并
// 合并分片
function mergeChunks (fileName, chunks, callback) {
console.log(‘chunks:‘ + chunks)
let chunkPaths = chunks.map(function (name) {
return path.join(process.env.IMAGESDIR, name)
})
// 采用Buffer方式合并
const readStream = function (chunkArray, cb) {
let buffers = []
chunkPaths.forEach(function (path) {
let buffer = fs.readFileSync(path)
buffers.push(buffer)
})
let concatBuffer = Buffer.concat(buffers)
let concatFilePath = path.join(process.env.IMAGESDIR, fileName)
fs.writeFileSync(concatFilePath, concatBuffer)
chunkPaths.forEach(function (path) {
fs.unlinkSync(path)
})
cb()
}
readStream(chunkPaths, callback)
}
buffer方式合并是一种常见的文件合并方式,方法是将各个分片文件分别用fs.readFile()方式读取,然后通过Buffer.concat()进行合并。
这种方法简单易理解,但有个最大的缺点,就是你读取的文件有多大,合并的过程占用的内存就有多大,因为我们相当于把这个大文件的全部内容都一次性载入到内存中了,这是非常低效的。同时,Node默认的缓冲区大小的上限是2GB,一旦我们上传的大文件超出2GB,那使用这种方法就会失败。虽然可以通过修改缓冲区大小上限的方法来规避这个问题,但是鉴于这种合并方式极吃内存,我不建议您这么做。
那么,有更好的方式吗?那是当然,下面介绍一种stream合并方式。
2、sream流合并
// 合并分片
function mergeChunks (fileName, chunks, callback) {
console.log(‘chunks:‘ + chunks)
let chunkPaths = chunks.map(function (name) {
return path.join(process.env.IMAGESDIR, name)
})
// 采用Stream方式合并
let targetStream = fs.createWriteStream(path.join(process.env.IMAGESDIR, fileName))
const readStream = function (chunkArray, cb) {
let path = chunkArray.shift()
let originStream = fs.createReadStream(path)
originStream.pipe(targetStream, {end: false})
originStream.on(‘end‘, function () {
// 删除文件
fs.unlinkSync(path)
if (chunkArray.length > 0) {
readStream(chunkArray, callback)
} else {
cb()
}
})
}
readStream(chunkPaths, callback)
}
为什么说流更好呢?流到底是什么呢?
流是数据的集合 —— 就像数组或字符串一样。区别在于流中的数据可能不会立刻就全部可用,并且你无需一次性的把这些数据全部放入内存。这使得流在操作大量数据或是数据从外部来源逐段发送过来的时候变得非常有用。
换句话说,当你使用buffer方式来处理一个2GB的文件,占用的内存可能是2GB以上,而当你使用流来处理这个文件,可能只会占用几十个M。这就是我们为什么选择流的原因所在。
在Node.js中,有4种基本类型的流,分别是可读流,可写流,双向流以及变换流。
所有的流都是EventEmitter的实例。它们发出可用于读取或写入数据的事件。然而,我们可以利用pipe方法以一种更简单的方式使用流中的数据。
在上面那段代码中,我们首先通过fs.createWriteStream()创建了一个可写流,用来存放最终合并的文件。然后使用fs.createReadStream()分别读取各个分片后的文件,再通过pipe()方式将读取的数据像倒水一样“倒”到可写流中,到监控到一杯水倒完后,马上接着倒下一杯,直到全部倒完为止。此时,全部文件合并完毕。
3、追加文件方式合并
追加文件方式合并指的是使用fs.appendFile()的方式来进行合并。
fs.appendFile()的作用是异步地追加数据到一个文件,如果文件不存在则创建文件。data可以是一个字符串或buffer。
使用这种方法也可以将文件合并,性能强过buffer合并方式,但不及流合并方式。
三种方式各有各的特点,但是在大文件合并上,我推荐使用流方式合并,流合并占内存最少,效率最高,是处理大文件的最佳选择。
标签:来源 外部 blob span 生成 性能 理解 好的 data
原文地址:https://www.cnblogs.com/goloving/p/12825973.html