根据url链接下载文件到本地代码

39 阅读1分钟
const fs = require('fs');
const path = require('path');
const axios = require('axios');

/**
 * 下载文件到本地
 * @param {string} fileUrl - 文件的远程URL
 * @param {string} targetDir - 本地目标文件夹(如 './downloads')
 * @param {string} [fileName] - 自定义文件名(可选,默认从URL或响应头获取)
 */
async function downloadFile(fileUrl, targetDir, fileName) {
  try {
    // 1. 确保目标文件夹存在
    if (!fs.existsSync(targetDir)) {
      fs.mkdirSync(targetDir, { recursive: true });
    }

    // 2. 发送HTTP请求(流式响应)
    const response = await axios({
      method: 'get',
      url: fileUrl,
      responseType: 'stream', // 重要:以流的形式接收数据
    });

    // 3. 确定文件名(优先级:自定义名称 > URL中的文件名 > 响应头中的文件名)
    let finalFileName = fileName;
    if (!finalFileName) {
      // 从URL中提取文件名(如 https://example.com/file.zip -> 'file.zip')
      const urlFileName = path.basename(new URL(fileUrl).pathname);
      if (urlFileName) finalFileName = urlFileName;

      // 尝试从响应头获取文件名(如 Content-Disposition: attachment; filename="example.pdf")
      const contentDisposition = response.headers['content-disposition'];
      if (contentDisposition) {
        const match = contentDisposition.match(/filename="?(.+?)"?(;|$)/i);
        if (match?.[1]) finalFileName = match[1];
      }
    }

    if (!finalFileName) {
      throw new Error('无法确定文件名,请通过参数手动指定。');
    }

    // 4. 拼接本地保存路径
    const filePath = path.join(targetDir, finalFileName);

    // 5. 创建可写流并保存文件
    const writer = fs.createWriteStream(filePath);
    response.data.pipe(writer);

    return new Promise((resolve, reject) => {
      writer.on('finish', () => resolve(filePath));
      writer.on('error', reject);
    });
  } catch (error) {
    throw new Error(`下载失败: ${error.message}`);
  }
}
/**
 * 批量下载文件(支持并发控制)
 * @param {Array} urls - 文件URL列表
 * @param {string} targetDir - 保存目录
 * @param {number} [concurrency=3] - 并发数
 */
async function batchDownload(urls, targetDir, concurrency = 3) {
  const results = [];
  const queue = [...urls];

  async function processQueue() {
    while (queue.length > 0) {
      const url = queue.shift();
      try {
        const filePath = await downloadFile(url, targetDir);
        results.push({ url, status: 'success', path: filePath });
        console.log(`✅ 下载成功: ${url} -> ${filePath}`);
      } catch (error) {
        results.push({ url, status: 'failed', error: error.message });
        console.error(`❌ 下载失败: ${url} - ${error.message}`);
      }
    }
  }

  // 启动并发任务
  const workers = Array(concurrency).fill().map(processQueue);
  await Promise.all(workers);

  return results;
}

// 使用示例
(async () => {
  const fileUrls = [
    'https://example.com/file1.pdf',
    'https://example.com/file2.zip',
    'https://example.com/file3.jpg',
    // 添加更多URL...
  ];

  const targetDir = './name_downloads'; // 本地文件夹
  const concurrency = 2; // 并发数(根据网络调整)

  console.log('开始批量下载...');
  const results = await batchDownload(fileUrls, targetDir, concurrency);

  console.log('\n下载统计:');
  console.table(results);
})();

测试运行

  1. 将代码保存为 download.js

  2. 在终端执行:

    bash

    node download.js
    
  3. 成功时输出类似:

    text

    文件已保存到: ./downloads/sample.pdf