使用Axios下载文件后无法读取,是否需promisify函数?
问题:使用Axios下载文件后无法读取文件内容
我声明了一个使用axios下载文件的download_file()函数,代码如下:
async function download_file(url, filename) { const file_stream = fs.createWriteStream(filename); await axios({ method: "GET", url: url, responseType: "stream", }) .then(function (response) { response.data.pipe(file_stream); }) .catch(function (error) { console.error(error); }); file_stream.on("finished", () => { file_stream.close(); }); }
随后我尝试下载一张PNG文件并读取它:
await download_file( "https://assets.vercel.com/image/upload/v1662090959/front/nextjs/twitter-card.png", "twitter.png" ); // 调用download_file()函数后无法正常读取文件 const data = fs.readFileSync("twitter.png", { encoding: "utf8" }); console.log(data);
但控制台无输出。不过直接读取未通过该函数下载的PNG文件时,能正常打印数据。我认为已await axios请求,无需对download_file()函数进行promisify,请问我的代码究竟哪里出错了?
解决方案
你的问题核心在于:await axios(...)只等待了HTTP请求的响应头和流的启动,并没有等待文件流写入完成。当download_file函数执行完毕返回时,文件可能还在写入过程中,此时调用readFileSync读取的是不完整(甚至是空)的文件,自然没有输出。
修改方法是让download_file函数等待文件写入完成,具体可以通过返回一个Promise来实现,监听文件流的finish和error事件:
async function download_file(url, filename) { return new Promise((resolve, reject) => { const file_stream = fs.createWriteStream(filename); axios({ method: "GET", url: url, responseType: "stream", }) .then(function (response) { // 管道流完成时触发resolve response.data.pipe(file_stream).on('finish', resolve); }) .catch(function (error) { console.error(error); reject(error); }); // 处理文件流自身的写入错误 file_stream.on('error', (err) => { console.error('文件写入错误:', err); reject(err); }); }); }
这样修改后,await download_file(...)会真正等待整个文件写入完成,之后再调用readFileSync就能读取到完整的文件内容了。
另外补充:PNG是二进制文件,用{ encoding: "utf8" }读取大概率会出现乱码,建议去掉encoding选项读取Buffer,或根据实际需求选择合适的编码格式。
内容的提问来源于stack exchange,提问作者Artaza Sameen
相关产品推荐
相关产品推荐

