FastDFS之文件上传/下载/删除

1、FastDFS简介

FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

FastDFS 架构包括 Tracker server 和 Storage server。客户端请求 Tracker server 进行文件上传、下载,通过Tracker server 调度最终由 Storage server 完成文件上传和下载。Tracker server 作用是负载均衡和调度,通过 Tracker server 在文件上传时可以根据一些策略找到Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storageserver 没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。可以将storage称为存储服务器

2、文件上传流程

客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID 用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名

组名:文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。
虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推。
数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

3、搭建文件存储微服务

创建文件管理微服务 service_file,该工程主要用于实现文件上传以及文件删除等功能。

3.1 修改pom.xml,引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring‐boot‐starter‐web</artifactId>
    </dependency>
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs‐client‐java</artifactId>
        <version>1.27.0.0</version>
      </dependency>
</dependencies>

3.2 在resources文件夹下创建fasfDFS的配置文件fdfs_client.conf

# 连接超时时间,单位为秒。
connect_timeout=60
# 通信超时时间,单位为秒
network_timeout=60
# 字符集
charset=utf-8
# tracker的http端口:浏览器访问
http.tracker_http_port=8080
# Tracker服务器与外界通信的IP和端口:Java程序访问
tracker_server=192.168.33.133:22122

3.3 在resources文件夹下创建application.yml

server:
  port: 18082
spring:
  application:
    name: file
  servlet:
    multipart:
      max‐file‐size: 10MB
      max‐request‐size: 10MB
  main:
    allow‐bean‐definition‐overriding: true # 当遇到同样名字的时候,是否允许覆盖注册
eureka:
  client:
    service‐url:
      defaultZone: http://127.0.0.1:7001/eureka
  instance:
    prefer‐ip‐address: true
  • max-file-size是单个文件大小
  • max-request-size是设置总上传的数据大小

3.4 创建启动类

@SpringBootApplication
@EnableEurekaClient
public class FileApplication {
    public static void main(String[] args) {
        SpringApplication.run(FileApplication.class);
    }
}

4、文件上传示例代码

4.1 文件信息封装

文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的md5值、文件的作者等相关属性,我们可以创建一个对象封装这些属性。

@Getter
@Setter
public class FastDFSFile {
    // 文件名字
    private String name;
    // 文件内容
    private byte[] content;
    // 文件扩展名
    private String ext;
    // 文件MD5摘要值
    private String md5;
    // 文件创建作者
    private String author;

    public FastDFSFile(String name, byte[] content, String ext, String
            height,String width, String author) {
        this.name = name;
        this.content = content;
        this.ext = ext;
        this.author = author;
    }

    public FastDFSFile(String name, byte[] content, String ext) {
        super();
        this.name = name;
        this.content = content;
        this.ext = ext;
    }

}

4.2、文件操作工具类

@Slf4j
public class FastDFSUtils {
    static {
       try{
           // 获得配置文件路径
           String file = new ClassPathResource("fsdf_client.conf").getPath();
           // 加载tracker配置信息
           ClientGlobal.init(file);
       } catch(Exception e){
           e.printStackTrace();
       }
    }

    /**
     * 文件上传方法
     * @param file
     * @return
     */
    public static String[] upload(FastDFSFile file) {
        // 获取文件的作者
        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] = new NameValuePair("author", file.getAuthor());
        // 接收返回数据
        String[] uploadResults = null;
        StorageClient storageClient = null;
        try {
            // 创建StorageClient客户端对象
            storageClient = getStorageClient();
            /**
             *  1)文件字节数组
             *  2)文件扩展名
             *  3)文件作者
             */
            uploadResults = storageClient.upload_file(file.getContent(),file.getExt(),meta_list);
        } catch (Exception e){
            log.error("Exception when uploadind the file:" +
                    file.getName(), e);
        }
        if (uploadResults == null && storageClient!=null) {
            log.error("upload file fail, error code:" +
                    storageClient.getErrorCode());
        }
        // 获取组名
        String groupName = uploadResults[0];
        // 获取文件存储路径
        String remoteFileName = uploadResults[1];
        return uploadResults;
    }


    /**
     * 文件下载
     * @param groupName  文件所在组名:group1
     * @param remoteFileName  文件的存储路径名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
     * @return
     */
    public static InputStream downloadFile(String groupName,String remoteFileName) throws Exception {
        // 1. 获得Storage客户端
        StorageClient storageClient = getStorageClient();
        // 2. 下载文件
        byte[] buf = storageClient.download_file(groupName, remoteFileName);
        // 3. 将字节数组转换为输入流
        return new ByteArrayInputStream(buf);
    }

    /** 文件删除
     * @param groupName  文件所在组名:group1
     * @param remoteFileName  文件的存储路径名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
     */
    public static void deleteFile(String groupName,String remoteFileName) throws Exception{
        getStorageClient().delete_file(groupName, remoteFileName);
    }

    /**
     * 获取文件信息
     * @param groupName  文件所在组名:group1
     * @param remoteFileName  文件的存储路径名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
     * @return
     */
    public static FileInfo getFileInfo(String groupName, String remoteFileName) throws Exception {
        return getStorageClient().get_file_info(groupName, remoteFileName);
    }

    /**
     * 获取Tracker的信息
     * @throws Exception
     */
    public static String getTrackerInfo() throws IOException{
        // 获取TrackerServer对象
        TrackerServer trackerServer = getTrackerServer();
        // 获得Tracker的IP和端口
        String ip = trackerServer.getInetSocketAddress().getHostString();
        int port = ClientGlobal.getG_tracker_http_port();
        return "http://"+ip+":"+port+"/";
    }


    /**
     * * 获取Storage客户端
     */
    private static StorageClient getStorageClient() throws IOException {
        TrackerServer trackerServer = getTrackerServer();
        StorageClient storageClient = new StorageClient(trackerServer,
                null);
        return storageClient;
    }

    /*
     **
     * 获取Tracker服务器
     */
    private static TrackerServer getTrackerServer() throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerServer;
    }
}

4.3、文件上传控制器

@RestController
@CrossOrigin
public class FileController {

    @PostMapping("/upload")
    public Result uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        // 创建FastDFSFile对象:封装文件数据
        FastDFSFile fastDFSFile = new FastDFSFile(
                file.getOriginalFilename(),
                file.getBytes(),
                StringUtils.getFilenameExtension(file.getOriginalFilename()));
        // 调用工具类方法执行上传
        String[] uploadResults = FastDFSUtils.upload(fastDFSFile);
        // 获取组名
        String groupName = uploadResults[0];
        // 获取文件存储路径
        String remoteFileName = uploadResults[1];
        // 拼接访问地址
        String url = FastDFSUtils.getTrackerInfo() +groupName+"/"+remoteFileName;
        return new Result(true, StatusCode.OK, "上传成功",url);
    }
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
FastDFS 是一个开源的轻量级分布式文件系统,它主要解决了海量文件存储问题,具有高性能、高可靠性、易扩展性等特点。下面介绍一下 FastDFS文件删除和预览操作。 1. 文件 FastDFS文件分为两步,第一步是上文件FastDFS 服务器,第二步是保存文件元数据到数据库中。 上文件FastDFS 服务器: ```python import os from fdfs_client.client import Fdfs_client # 定义 FastDFS 配置文件路径 FDFS_CLIENT_CONF = '/etc/fdfs/client.conf' # 创建 Fdfs_client 对象 client = Fdfs_client(FDFS_CLIENT_CONF) # 上本地文件 ret = client.upload_by_filename('/path/to/local/file') if ret.get('Status') == 'Upload successed.': # 获取文件 ID file_id = ret.get('Remote file_id') else: # 上失败 file_id = None ``` 保存文件元数据到数据库中: ```python from sqlalchemy.orm import sessionmaker from models import File from database import engine # 创建数据库连接 Session = sessionmaker(bind=engine) session = Session() # 创建文件对象并保存到数据库中 file = File(file_id=file_id, filename='example.txt', size=os.path.getsize('/path/to/local/file')) session.add(file) session.commit() ``` 2. 文件删除 FastDFS文件删除也分为两步,第一步是删除 FastDFS 服务器上的文件,第二步是从数据库中删除文件元数据。 删除 FastDFS 服务器上的文件: ```python from fdfs_client.client import Fdfs_client # 创建 Fdfs_client 对象 client = Fdfs_client(FDFS_CLIENT_CONF) # 删除文件 ret = client.delete_file(file_id) if ret == 0: # 删除成功 pass else: # 删除失败 pass ``` 从数据库中删除文件元数据: ```python from sqlalchemy.orm import sessionmaker from models import File from database import engine # 创建数据库连接 Session = sessionmaker(bind=engine) session = Session() # 获取文件对象并从数据库中删除 file = session.query(File).filter_by(file_id=file_id).first() if file: session.delete(file) session.commit() ``` 3. 文件预览 FastDFS文件预览需要在客户端下载文件并提供预览功能,具体实现方式根据业务需求而定。例如,可以使用 Flask 框架提供 Web 服务,通过浏览器访问预览页面。 ```python from flask import Flask, send_file from fdfs_client.client import Fdfs_client # 创建 Flask 应用 app = Flask(__name__) # 定义 FastDFS 配置文件路径 FDFS_CLIENT_CONF = '/etc/fdfs/client.conf' @app.route('/preview/<file_id>') def preview(file_id): # 创建 Fdfs_client 对象 client = Fdfs_client(FDFS_CLIENT_CONF) # 下载文件到本地 ret = client.download_to_buffer(file_id) if ret.get('Content') is not None: # 返回文件内容 return send_file(ret.get('Content'), attachment_filename='example.txt') else: # 下载失败 return 'Download failed.' if __name__ == '__main__': app.run() ``` 在浏览器中访问 http://localhost:5000/preview/{file_id} 即可预览文件
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fkjaios_xkp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值