nodejs 上传文件,怎么去重?好像有一种hash文件方式存储?

如题,好像有一种获取文件的hash对比来判断是否同一张图?怎么实现呢?

阅读 1.9k
avatarAI BotBETA

在 Node.js 中通过文件哈希值(如 MD5、SHA-256)去重是常见方法,可避免相同文件重复存储。以下是完整实现步骤和代码示例:


核心步骤

  1. 计算文件哈希:读取上传文件流,用 crypto 模块生成哈希值
  2. 查询哈希库:检查该哈希值是否已存在于数据库/缓存中
  3. 存储逻辑

    • 如哈希存在 → 返回已有文件(跳过存储)
    • 如哈希不存在 → 存储文件并将哈希值写入记录

代码实现

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');

// 示例:计算文件的 MD5 哈希 (改用 sha256 更安全)
function getFileHash(filePath) {
  return new Promise((resolve, reject) => {
    const hash = crypto.createHash('md5');
    const stream = fs.createReadStream(filePath);

    stream.on('data', (chunk) => hash.update(chunk));
    stream.on('end', () => resolve(hash.digest('hex')));
    stream.on('error', reject);
  });
}

// 处理上传中间件 (Express示例)
app.post('/upload', async (req, res) => {
  if (!req.files || !req.files.file) {
    return res.status(400).send('No file uploaded');
  }

  const uploadedFile = req.files.file;
  const tempPath = uploadedFile.tempFilePath;

  try {
    // 1. 计算哈希值
    const fileHash = await getFileHash(tempPath);

    // 2. 检查哈希值是否存在(此处用 Map 模拟,实际用数据库/Redis)
    if (fileHashRegistry.has(fileHash)) {
      fs.unlinkSync(tempPath); // 删除临时文件
      return res.send(`文件已存在,路径: ${fileHashRegistry.get(fileHash)}`);
    }

    // 3. 存储新文件(实际存储路径按业务设计)
    const savePath = path.join(__dirname, 'uploads', fileHash + path.extname(uploadedFile.name));
    fs.renameSync(tempPath, savePath);

    // 4. 记录哈希值 → 路径映射
    fileHashRegistry.set(fileHash, savePath);

    res.send(`文件保存成功:${savePath}`);
  } catch (err) {
    res.status(500).send(`处理失败: ${err.message}`);
  }
});

// 模拟存储(实际替换为数据库)
const fileHashRegistry = new Map();

关键优化建议

  1. 哈希算法选择

    • MD5:计算快,但有极低碰撞风险
    • SHA-256:更安全但略慢(推荐)

      crypto.createHash('sha256')
  2. 大文件处理

    • 必须使用流(Stream)避免内存溢出
    • 示例中 createReadStream 已支持 GB 级文件
  3. 持久化存储

    • 生产环境用 Redis 存哈希→路径映射(快速查询)
    • 数据库字段:file_hash(唯一索引)、file_pathupload_time
  4. 文件名冲突处理

    • 保存时舍弃原文件名,直接用哈希值 + 扩展名(如 d41d8cd98f00b204e9800998ecf8427e.jpg
  5. 图像专用优化

    • 如需识别「视觉相同但二进制不同」的图片(如压缩后),需用 感知哈希(Perceptual Hash, pHash)
    • 推荐库:sharp + phash(计算图像特征值)

典型去重流程图

graph TD
    A[客户端上传文件] --> B[保存为临时文件]
    B --> C[计算文件哈希值]
    C --> D{哈希值是否存在?}
    D -->|是| E[删除临时文件<br>返回已有文件信息]
    D -->|否| F[文件重命名:哈希 + 扩展名]
    F --> G[移动到存储目录]
    G --> H[记录哈希路径映射]
    H --> I[返回成功信息]

通过文件哈希去重可节省 90%+ 的存储空间(当重复率高时),同时减少磁盘 I/O 压力。

1 个回答

读取文件内容然后通过 hash 计算即可得到。具体方案几乎所有 AI 都能给出,比如上面的 AI Bot。AI 对这种小功能点,调用函数一步给出答案,是非常擅长的。要善用。

推荐问题