nestjs文件上传与下载

152 阅读1分钟

文件上传

文件上传

Nest.js 实战 (五):如何实现文件本地上传

Nest 实现文件上传的功能

文件上传并保存到sqlite

npm install @nestjs/platform-express multer @nestjs/typeorm typeorm sqlite3
// file.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class File {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  filename: string;

  @Column('blob') // 使用 blob 类型存储文件二进制数据
  data: Buffer;

  @Column()
  mimetype: string;

  @Column()
  size: number;
}
// file.controller.ts
import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { FileService } from './file.service';
import { File } from './file.entity';

@Controller('files')
export class FileController {
  constructor(private readonly fileService: FileService) {}

  @Post('upload')
  @UseInterceptors(FileInterceptor('file')) // 'file' 是表单字段名
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
    return this.fileService.saveFile(
      file.buffer,        // 文件二进制数据
      file.originalname, // 文件名
      file.mimetype,     // MIME 类型
      file.size,         // 文件大小
    );
  }
}
// file.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { File } from './file.entity';

@Injectable()
export class FileService {
  constructor(
    @InjectRepository(File)
    private fileRepository: Repository<File>,
  ) {}

  async saveFile(
    data: Buffer,
    filename: string,
    mimetype: string,
    size: number,
  ): Promise<File> {
    const newFile = this.fileRepository.create({
      filename,
      data,
      mimetype,
      size,
    });
    return this.fileRepository.save(newFile);
  }
}

从sqlite读取数据,并写入本地

// file.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { File } from './file.entity';
import * as fs from 'fs';

@Injectable()
export class FileService {
  constructor(
    @InjectRepository(File)
    private fileRepository: Repository<File>,
  ) {}

  async saveFileToDisk(id: number, outputPath: string): Promise<void> {
    const fileRecord = await this.fileRepository.findOneBy({ id });
    if (!fileRecord) {
      throw new Error('File not found');
    }

    // 将 BLOB 数据写入本地文件
    fs.writeFileSync(outputPath, fileRecord.data);
  }
}
// 在 saveFileToDisk 方法中追加:
const directory = '/path/to/save'; // 目标目录
const outputPath = `${directory}/${fileRecord.filename}`;

// 确保目录存在
if (!fs.existsSync(directory)) {
  fs.mkdirSync(directory, { recursive: true });
}

// 写入文件
fs.writeFileSync(outputPath, fileRecord.data);
console.log(`File saved to: ${outputPath}`);

electron主动向渲染进程发消息

// 主进程 - main.js
const { BrowserWindow, ipcMain } = require('electron');

function sendMessageToRenderer() {
  const win = BrowserWindow.getFocusedWindow(); // 获取当前窗口
  if (win) {
    win.webContents.send('push-notification', { 
      title: '新消息', 
      content: '您有一条待处理任务' 
    });
  }
}

// 定时推送示例
setInterval(sendMessageToRenderer, 5000);
// 渲染进程 - renderer.js
const { ipcRenderer } = require('electron');

ipcRenderer.on('push-notification', (event, data) => {
  console.log('收到推送:', data.title, data.content);
  // 更新UI或显示通知
});

预加载脚本安全暴露API

// preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  onPush: (callback) => ipcRenderer.on('push-notification', callback)
});

前端调用

// 渲染进程 - 前端页面
window.electronAPI.onPush((event, data) => {
  alert(`通知:${data.title}\n${data.content}`);
});

文件下载

流式文件