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

Node.js中使用pipe时能否借助writeStream.bytesWritten监控复制速度?

Hey there! Let's break down why you're seeing 0 for bytesWritten and how to fix this to get your progress bar, speed tracking, and remaining time estimates working properly.

What's Going Wrong Here?

  1. pipe is asynchronous, but your do...while loop runs synchronously
    When you call readableStream.pipe(firstCopy), Node.js starts the file transfer in the background—it doesn't pause the loop to wait for the transfer to start or finish. Your console.log(firstCopy.bytesWritten) runs immediately after kicking off the pipe, before any bytes have actually been written. That's why you get 0 every time. On top of that, your loop will blast through all files at once, starting every copy task simultaneously instead of waiting for one to finish before the next.

  2. bytesWritten works with pipe—you just need to read it at the right time
    The bytesWritten property of a WriteStream does update in real-time as pipe writes data. The problem isn't the property itself, it's that you're checking it too early, before any actual writing has happened.

How to Fix It

Let's fix the async loop issue first, then add proper progress monitoring.

Step 1: Use Async/Await for Controlled File Copies

Instead of a synchronous do...while, we'll wrap the copy logic in an async function and use a regular for loop with await to wait for each file to finish copying before moving on. This gives you control over whether you copy files sequentially or in parallel.

Step 2: Track Progress in Real-Time

We'll:

  • Grab the total size of the source file first (to calculate progress percentage)
  • Set up an interval to check bytesWritten every second
  • Calculate transfer speed and remaining time based on the data we collect

Full Working Example

const fs = require('fs');
const path = require('path');
const { promisify } = require('util');

// Convert callback-based fs methods to promise-based for async/await
const stat = promisify(fs.stat);

// Helper function to wait for a stream to finish (or error out)
const waitForStream = (stream) => {
  return new Promise((resolve, reject) => {
    stream.on('finish', resolve);
    stream.on('error', reject);
  });
};

async function copyWithProgress(fileList, copyPathOne, copyPathTwo, fileName) {
  for (let i = 0; i < fileList.length; i++) {
    const sourceFile = fileList[i];
    const dest1 = path.join(copyPathOne, fileName[i]);
    const dest2 = path.join(copyPathTwo, fileName[i]);

    // Get total size of the source file for progress calculations
    const fileStats = await stat(sourceFile);
    const totalBytes = fileStats.size;

    // Create our streams
    const readStream = fs.createReadStream(sourceFile);
    const writeStream1 = fs.createWriteStream(dest1);
    const writeStream2 = fs.createWriteStream(dest2);

    // Start piping data to both destinations
    readStream.pipe(writeStream1);
    readStream.pipe(writeStream2);

    const startTime = Date.now();
    // Set up an interval to log progress every second
    const progressInterval = setInterval(() => {
      const written = writeStream1.bytesWritten; // Both streams should have identical progress
      const progressPercent = ((written / totalBytes) * 100).toFixed(2);
      const speedMBps = (written / 1024 / 1024 / ((Date.now() - startTime) / 1000)).toFixed(2);
      const remainingBytes = totalBytes - written;
      const remainingSeconds = remainingBytes > 0 ? (remainingBytes / (written / ((Date.now() - startTime) / 1000)) / 1000).toFixed(2) : 0;

      console.log(`[${fileName[i]}] Progress: ${progressPercent}% | Speed: ${speedMBps} MB/s | Remaining: ${remainingSeconds}s`);
    }, 1000);

    // Wait for both writes to finish, then clean up the interval
    try {
      await Promise.all([waitForStream(writeStream1), waitForStream(writeStream2)]);
      clearInterval(progressInterval);
      console.log(`✅ ${fileName[i]} copied successfully!`);
    } catch (err) {
      clearInterval(progressInterval);
      console.error(`❌ Failed to copy ${fileName[i]}:`, err);
    }
  }
}

// Call the function with your existing variables
// copyWithProgress(fileList, copyPathOne, copyPathTwo, fileName);

Quick Notes

  • Why this works: We wait for each file's copy streams to emit the finish event before moving to the next file, and our interval checks bytesWritten while the transfer is in progress—so we get real, non-zero values.
  • Parallel vs Sequential: If you want to copy multiple files at once instead of one after another, you could collect all copy promises into an array and use Promise.all()—just be mindful of system resource limits with large files.
  • Your earlier error: writeStream.bytesWritten(firstCopy) failed because bytesWritten is a property, not a method. The correct syntax is firstCopy.bytesWritten—you just were using it at the wrong time!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:27:19