You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用createReadStream、createWriteStream及yauzl迁移压缩图片报错排查

问题排查与yauzl正确实现指导

问题概述

开发任务:用户输入目录名和图片名后,将指定目录中的压缩图片通过流结合yauzl包迁移至temp目录。当前代码运行触发EISDIR错误,相关信息如下:

原代码

import fs, { createReadStream } from "fs";
import inquirer from "inquirer";
import terminalKit from "terminal-kit";
import yauzl from "yauzl";

inquirer
  .prompt([
    {
      type: "input",
      name: "catalog_name",
      message: "Enter catalog name:",
    },
    {
      type: "input",
      name: "image_name",
      message: "Enter image name:",
    },
  ])
  .then((answers) => {
    const catalogName = answers.catalog_name;
    const imageName = answers.image_name;
    const filePath = `./${catalogName}/${imageName}`;
    if (!fs.existsSync(`./${catalogName}`)) {
      throw new Error("Catalog does not exist!");
    }

    if (fs.existsSync(catalogName)) {
      fs.readdir(catalogName, (err, files) => {
        const fileDirectoryArr = files;
        if (fileDirectoryArr.includes(imageName)) {
          const readStream = createReadStream("./images");
          const writeStream = fs.createWriteStream("./temp");
          readStream.pipe(writeStream);
        } else {
          throw new Error("Image does not exist!");
        }
      });
    }
  })
  .catch((error) => {
    console.log("Something went wrong!", error);
  });

错误信息

node:events:491
      throw er; // Unhandled 'error' event
      ^
Error: EISDIR: illegal operation on a directory, open 'C:\Users\jkuki\Desktop\ONL_FSF_E_16_Egzamin_1\01_Strumienie\temp'
Emitted 'error' event on WriteStream instance at:
    at WriteStream.onerror (node:internal/streams/readable:773:14)
    at WriteStream.emit (node:events:513:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -4068,
  code: 'EISDIR',
  syscall: 'open',
  path: 'C:\\Users\\jkuki\\Desktop\\ONL_FSF_E_16_Egzamin_1\\01_Strumienie\\temp'
}

目录结构

根目录下存在images、temp两个目录,images目录内存放压缩格式的图片文件。


错误原因分析

  1. 流操作目标错误:createReadStream("./images")指向目录而非具体压缩文件,createWriteStream("./temp")同样指向目录,Node.js流无法直接对目录进行读写,这是触发EISDIR错误的直接原因。
  2. 未使用yauzl核心功能:代码导入了yauzl包但未调用,完全没实现读取压缩文件的逻辑。
  3. 异步错误无法捕获:fs.readdir回调中抛出的错误无法被外层.catch捕获,会导致未处理异常。
  4. 逻辑冗余:重复判断目录是否存在,多余且无意义。

修复方案与正确实现

关键修复点

  • 确保读写流指向具体文件而非目录
  • 基于yauzl实现压缩文件的读取与图片提取逻辑
  • 用Promise封装异步操作,统一错误捕获
  • 提前创建temp目录(若不存在)

正确代码

import fs from "fs/promises";
import { createWriteStream } from "fs";
import inquirer from "inquirer";
import yauzl from "yauzl";

// 确保temp目录存在
const ensureTempDir = async () => {
  try {
    await fs.access("./temp");
  } catch {
    await fs.mkdir("./temp");
  }
};

inquirer
  .prompt([
    {
      type: "input",
      name: "catalog_name",
      message: "输入目录名:",
    },
    {
      type: "input",
      name: "image_name",
      message: "输入图片名:",
    },
  ])
  .then(async (answers) => {
    const catalogName = answers.catalog_name;
    const imageName = answers.image_name;
    const zipFilePath = `./${catalogName}/${imageName}`;

    // 检查目录是否存在
    try {
      await fs.access(`./${catalogName}`);
    } catch {
      throw new Error("目录不存在!");
    }

    // 检查压缩文件是否存在
    try {
      await fs.access(zipFilePath);
    } catch {
      throw new Error("指定的压缩图片文件不存在!");
    }

    await ensureTempDir();

    // 使用yauzl读取zip文件并提取目标图片
    return new Promise((resolve, reject) => {
      yauzl.open(zipFilePath, { lazyEntries: true }, (err, zipfile) => {
        if (err) return reject(err);

        zipfile.readEntry();
        zipfile.on("entry", (entry) => {
          // 匹配压缩包内的目标图片(可根据实际文件名规则调整匹配逻辑)
          const targetImageName = imageName.replace(/\.zip$/, "");
          if (entry.fileName === targetImageName) {
            zipfile.openReadStream(entry, (err, readStream) => {
              if (err) return reject(err);
              const writeStream = createWriteStream(`./temp/${entry.fileName}`);
              readStream.pipe(writeStream);
              writeStream.on("finish", () => {
                console.log(`图片已成功迁移至temp目录`);
                zipfile.close();
                resolve();
              });
              writeStream.on("error", (err) => reject(err));
            });
          } else {
            zipfile.readEntry(); // 跳过无关文件
          }
        });

        zipfile.on("error", (err) => reject(err));
        zipfile.on("close", () => resolve());
      });
    });
  })
  .catch((error) => {
    console.error("出错了!", error.message);
  });

代码说明

  1. ensureTempDir函数:异步检查并创建temp目录,避免写入时因目录不存在报错。
  2. Promise化异步操作:使用fs/promises替代回调式方法,同时将yauzl的操作封装为Promise,确保所有错误能被外层.catch捕获。
  3. yauzl核心逻辑:
    • 以lazyEntries模式打开压缩文件,按需读取内部条目
    • 遍历压缩包内的文件,匹配到目标图片后开启读取流
    • 将读取流管道到temp目录的写入流,完成后关闭zip文件
  4. 错误处理:统一捕获所有异步操作的错误,输出清晰的错误信息。

内容的提问来源于stack exchange,提问作者JKukielski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 21:11:29