createWriteStream完成后获取文件大小



我正在使用createWriteStream下载视频文件,当它完成后,我想获得它下载的文件的大小。

原因是,如果它试图下载的文件不存在,我的代码仍然会成功完成,而createWriteStream最终会写入一个零长度的文件。

如果我能确定文件大小,我就能确定它的零长度(失败(还是否(成功(。

这是我的代码:

export const downloadTempFileFromUrl = async (downloadUrl, ext) => {
return new Promise((resolve, reject) => {
const uuid = uuidv4()
const fileName = `${uuid}.${ext}`
const filePath = path.resolve(os.tmpdir(), fileName)
const writeStream = createWriteStream(filePath)
const htt = (downloadUrl.startsWith('https')) ? https : http
htt.get(downloadUrl, response => response.pipe(writeStream))
writeStream.on('close', () => resolve({ success: true, fileName, filePath, uuid, downloadUrl, writeStream }))
writeStream.on('error', () => reject({ success: false, fileName, filePath, uuid, downloadUrl, writeStream }))
})
}

调用代码很简单:

const response = await downloadTempFileFromUrl('http://server/path', 'mp4')
// how do I get the file size?
if (response.success) console.log(response.writeStream)

要在Node.js中获取文件的大小,可以使用内置fs模块提供的stat((方法。此方法异步工作,并列出给定路径中文件的统计信息。

您所需要做的就是将文件的路径和回调函数传递给fs.stat((方法。一旦Node.js填充了文件统计信息,它将使用两个参数调用回调函数:一个错误消息和文件统计信息:

const fs = require('fs');
// Read file stats
fs.stat('file.txt', (err, stats) => {
if (err) {
console.log(`File doesn't exist.`);
} else {
console.log(stats);
}
});

fs.stat((函数返回的stats对象如下所示:

Stats {
dev: 16777221,
mode: 33279,
nlink: 1,
uid: 501,
gid: 20,
rdev: 0,
blksize: 4096,
ino: 5172976,
size: 290,
blocks: 8,
atimeMs: 1606143471354.2327,
mtimeMs: 1599218860000,
ctimeMs: 1606074010041.4927,
birthtimeMs: 1605423684000,
atime: 2020-11-23T14:57:51.354Z,
mtime: 2020-09-04T11:27:40.000Z,
ctime: 2020-11-22T19:40:10.041Z,
birthtime: 2020-11-15T07:01:24.000Z
}

要获取文件的大小,可以使用stats对象中的size属性:

const size = stats.size; // 290 bytes

您可以尝试通过侦听data事件来检测流是否为空,并在事件被触发时更改标志。像这样:

let nonZero = false;
writeStream.on('data', () => nonZero = true);

然后使用nonZero标志解决承诺:

resolve({ success: nonZero, ... });

因此,如果data事件至少触发一次,则意味着流不为空,文件也不为空。

在流的close事件上获取fs.statsSync对我很有效。

const fileStream = fs.createWriteStream(TEST_FILE, { flags: 'a' });
// stream contents to file with fileStream.write(data)
fileStream.end();
fileStream.on('close', () => {
const fileStats = fs.statSync(TEST_FILE);
const fileSize = fileStats.size;
console.info(`File:${TEST_FILE} created with size:${fileSize}`);
});

我接受的答案是正确的,但对我来说有点太笼统了。以下是针对createWriteStream的答案。这只小狗很管用。

与前面的内容相比,主要的变化是使用finish事件而不是close事件。我读到这个事件只在成功时触发,而close事件也在错误时触发。并不是说这有多大区别。

然后,当finish事件触发时,代码会在解析之前获取文件统计信息。值得注意的是,Windows报告的零长度文件的长度很小,例如68字节,因此如果检测到零长度文件,则需要考虑到这一点。

export const downloadTempFileFromUrl = async (downloadUrl, ext) => {
return new Promise((resolve, reject) => {
const uuid = uuidv4()
const fileName = `${uuid}.${ext}`
const filePath = path.resolve(os.tmpdir(), fileName)
const writeStream = createWriteStream(filePath)
const htt = (downloadUrl.startsWith('https')) ? https : http
htt.get(downloadUrl, response => response.pipe(writeStream))
writeStream.on('finish', () => {
const VERY_SMALL_FILE_SIZE = 1000 // on Windows zero length files are reported to have a very small size - e.g. 68 bytes
const statsResponse = appStatSync(filePath)
const success = statsResponse.success && statsResponse.stats.size > VERY_SMALL_FILE_SIZE
resolve({ success, fileName, filePath, uuid, downloadUrl, writeStream, stats: statsResponse.stats })
})
writeStream.on('error', () => reject({ success: false, fileName, filePath, uuid, downloadUrl, writeStream, stats: null }))
})
}

appStatSync只是一个简单的包装器,如下所示:

import { statSync } from 'fs'
import { logger } from './logger.js'
export const appStatSync = filePath => {
try {
const stats = statSync(filePath)
return { success: true, stats, err: null }
} catch (err) {
logger.error('statSync error')
logger.error(err)
return { success: false, stats: null, err }
}
}

最新更新