基于Nodejs的工程如何保存小文件比较好?

基于Nodejs的工程如何保存小文件比较好?

假设我要做一个MP3下载网站, 封面的文件一般在10K以下, 再加上用户的头像, 也就是说我有大量的小图片需要存储 每个页面浏览时都会有很多图片请求

我需要这些小图片存的省,读得快

如何存放类似头像这样的小文件比较节省性能? GridFS? 直接保存在文件夹里面? 如果需要缓存的话应该用什么技术呢? 请大家畅所欲言, 教教我这个菜鸟

7 回复

对于基于Node.js的工程项目,特别是涉及到大量小文件(如MP3封面、用户头像等)的存储与读取,选择合适的存储方案非常重要。既要考虑存储效率,也要考虑读取速度。下面是几种常见的方案以及它们的优缺点。

1. 直接保存在文件系统中

优点:

  • 实现简单,不需要额外的库。
  • 对于小型项目来说,维护成本低。

缺点:

  • 随着文件数量增加,查找和管理文件变得困难。
  • 文件系统本身的性能瓶颈可能会限制读写速度。

示例代码:

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

// 保存文件
function saveFile(filePath, fileData) {
    fs.writeFileSync(filePath, fileData);
}

// 读取文件
function readFile(filePath) {
    return fs.readFileSync(filePath, 'utf8');
}

// 使用示例
saveFile(path.join(__dirname, 'avatar.jpg'), 'file data');
const fileContent = readFile(path.join(__dirname, 'avatar.jpg'));

2. 使用数据库(如MongoDB的GridFS)

优点:

  • 可以更好地管理和查询文件。
  • 数据库的备份和恢复机制更加成熟。

缺点:

  • 存储和读取文件可能比直接使用文件系统慢。
  • 需要额外配置和维护数据库。

示例代码:

const mongoose = require('mongoose');
const GridFsStorage = require('multer-gridfs-storage');
const Grid = require('gridfs-stream');
const conn = mongoose.connection;

let gfs;
conn.once('open', () => {
    gfs = Grid(conn.db, mongoose.mongo);
    gfs.collection('uploads'); // 声明集合名
});

// 保存文件到GridFS
function saveToGridFS(filename, fileData) {
    const writestream = gfs.createWriteStream({
        filename: filename,
        mode: 'w'
    });
    writestream.end(fileData);
}

// 从GridFS读取文件
function readFromGridFS(filename) {
    return new Promise((resolve, reject) => {
        gfs.files.findOne({filename: filename}, (err, file) => {
            if (!file || !file.length) {
                return reject(new Error(`File not found`));
            }
            const readstream = gfs.createReadStream({filename: filename});
            let fileData = '';
            readstream.on('data', chunk => fileData += chunk);
            readstream.on('end', () => resolve(fileData));
            readstream.on('error', reject);
        });
    });
}

3. 使用CDN或云存储服务(如AWS S3)

优点:

  • 提供高可用性和可扩展性。
  • 减轻服务器压力。

缺点:

  • 需要额外支付存储费用。
  • 配置和使用相对复杂。

示例代码(使用AWS SDK):

const AWS = require('aws-sdk');

AWS.config.update({
    accessKeyId: 'your-access-key-id',
    secretAccessKey: 'your-secret-access-key',
    region: 'your-region'
});

const s3 = new AWS.S3();

// 上传文件到S3
async function uploadToS3(key, fileData) {
    await s3.upload({
        Bucket: 'your-bucket-name',
        Key: key,
        Body: fileData
    }).promise();
}

// 从S3下载文件
async function downloadFromS3(key) {
    const data = await s3.getObject({Bucket: 'your-bucket-name', Key: key}).promise();
    return data.Body.toString();
}

总结

根据您的需求,如果文件数量较少且对性能要求不高,可以直接保存在文件系统中。如果需要更好的管理和查询功能,可以考虑使用GridFS。如果希望减轻服务器负担并获得高可用性,则可以考虑使用CDN或云存储服务。


数据存gridfs,前端通过nginx proxy_cache或者Varnish代理缓存下

我找了一些书, 上面说gridfs是用来存储大文件的, 尤其是流媒体文件, 存小文件时因为要读2次数据库, 所以反而会变慢, 再者我也不清楚这样返回存储小文件是否能正常返回304

都是特别小的文件可以直接存mongodb 二进制字节数组里面,不需要gridfs,我的用户头像就是是这么用的

用七牛得了,免费套餐够你用了~

本宝贵的建议, 以前真不知道这个东西, 不过我还是希望自己用nodejs解决这个问题

对于你的需求,保存小文件可以考虑多种方式。根据你描述的情况(大量的小文件且每个页面浏览时都有很多图片请求),可以选择内存缓存或者本地文件系统作为存储方案。GridFS更适合处理大文件或文件数量不是特别多的情况。

本地文件系统

保存小文件到本地文件系统是一种简单且高效的方法。你可以使用Node.js的内置fs模块来操作文件系统。

示例代码:

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

function saveFile(fileData, filename) {
    const filePath = path.join(__dirname, 'uploads', filename);
    fs.writeFile(filePath, fileData, (err) => {
        if (err) throw err;
        console.log(`File saved: ${filename}`);
    });
}

// 使用方法
saveFile(bufferOfImage, 'avatar.jpg');

优点:

  • 实现简单。
  • 性能较好,尤其是当文件较小。

缺点:

  • 文件数量过多时管理较复杂。
  • 可能会遇到磁盘空间限制。

内存缓存

为了进一步提高性能,你可以考虑使用内存缓存,如memcachedRedis等。

示例代码:

const redis = require('redis');
const client = redis.createClient();

async function saveToCache(filename, fileBuffer) {
    try {
        await client.set(filename, fileBuffer.toString('base64'));
        console.log(`File saved to cache: ${filename}`);
    } catch (error) {
        console.error('Error saving to cache:', error);
    }
}

async function getFromCache(filename) {
    try {
        const fileBuffer = Buffer.from(await client.get(filename), 'base64');
        console.log(`File retrieved from cache: ${filename}`);
        return fileBuffer;
    } catch (error) {
        console.error('Error retrieving from cache:', error);
    }
}

// 使用方法
saveToCache('avatar.jpg', bufferOfImage);
getFromCache('avatar.jpg');

优点:

  • 访问速度极快。
  • 减少磁盘I/O操作。

缺点:

  • 需要额外部署内存缓存服务。
  • 内存有限制,不适合非常大的文件。

结论

根据你的需求,建议先将小文件保存到本地文件系统,并使用内存缓存(如Redis)来提高读取性能。这种方式结合了两者的优势,既保证了文件的持久性存储,又提高了访问速度。

回到顶部