Tracker:标准服务端口22122、HTTP端口8080 Storage:标准服务端口23000、HTTP端口8888

文章目录
    • 一、架构
    • 二、文件上传、下载、删除
        • 1 时序图
        • 2 流程说明
          • 3 代码实现

一、架构

架构图:

Client:客户端。使用java语言编写的项目属于客户端。 Tracker Server:跟踪服务器,主要做调度工作,在访问上起负载均衡的作用。在内存中记录集群中group和storage server的状态信息,是连接Client和Storage server的枢纽。 Storage Server:存储服务器,文件和文件属性(meta data)都保存到存储服务器上

架构解读:

只有两个角色,tracker server和storage server,不需要存储文件索引信息。 所有服务器都是对等的,不存在Master-Slave关系。 存储服务器采用分组方式,同组内存储服务器上的文件完全相同(RAID 1)。 不同组的storage server之间不会相互通信。 由storage server主动向tracker server报告状态信息,tracker server之间不会相互通信。

二、文件上传、下载、删除 1 时序图

1.1 文件上传时序图

1.2 文件下载时序图

1.3 文件删除时序图

2 流程说明

2.1 上传流程说明

  1. 客户端访问Tracker
  2. Tracker 返回Storage的ip和端口
  3. 客户端直接访问Storage,把文件内容和元数据发送过去。
  4. Storage返回文件存储id。包含了组名和文件名

2.2 下载流程说明

  1. client询问tracker下载文件的storage,参数为文件标识(组名和文件名);
  2. tracker返回一台可用的storage;
  3. client直接和storage通讯完成文件下载。
3 代码实现

3.1 添加依赖


        
        
            cn.bestwu
            fastdfs-client-java
            1.27
        
        
            org.apache.commons
            commons-lang3
            3.9
        
    

3.2 编写配置文件 文件名:fdfs_client.conf 修改成自己的tracker服务器ip

connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8080

tracker_server = 192.168.14.129:22122

3.3 导入工具类 在com.bjsxt.utils.fdfs.FdfsFileSystemUtils下粘贴配置工具类

package com.bjsxt.utils.fdfs;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

import java.util.Arrays;


public class FdfsFileSystemUtils {
    // 通过static初始化代码块,读取配置文件,初始化客户端连接对象。
    // 客户端连接对象,用于实现文件读写操作使用。
    private static StorageClient storageClient;

    static {
        try {
            // 读取配置文件
            // 获取文件名称
            String path = Thread.currentThread().getContextClassLoader()
                    .getResource("").getPath() + "fdfs_config.conf";
            // 加载配置文件
            ClientGlobal.init(path);
            // 创建Tracker客户端对象
            TrackerClient trackerClient = new TrackerClient();
            // 创建Tracker服务器对象
            TrackerServer trackerServer = trackerClient.getConnection();
            // 创建Storage服务器对象
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            // 创建Storage客户端对象
            storageClient = new StorageClient(trackerServer, storageServer);
        }catch(Exception e){
            e.printStackTrace();
            // 初始化代码块出错,一定要抛出错误,停止虚拟机。
            throw new ExceptionInInitializerError(e);
        }
    }

    
    public static boolean deleteFile(String groupName, String fileName){
        try{
            // storageClient.delete_file(String groupName, String fileName);
            // groupName - 要删除的文件的卷名,就是保存文件的storage服务配置中的groupName
            // fileName - 要删除的文件的文件名,包含路径地址。格式:M00/目录/目录/文件名.后缀名
            // M00代表保存文件的目录, store_path0 。 目录/目录 - 保存文件的具体位置。
            int result = storageClient.delete_file(groupName, fileName);
            // 返回结果为0,代表删除成功,其他是删除失败。
            return result == 0;
        }catch(Exception e){
            e.printStackTrace();
            return false;
        }
    }

    
    public static byte[] downloadFile(String groupName, String fileName, NameValuePair[] metaDatas){
        try{
            
            byte[] datas = storageClient.download_file(groupName, fileName);
            // 要下载的文件的扩展信息。
            if(metaDatas != null) {
                NameValuePair[] tmp = storageClient.get_metadata(groupName, fileName);
                // 把查询到的文件扩展信息。保存到传入的数组中。
                for(int i = 0; i < tmp.length; i++){
                    metaDatas[i] = tmp[i];
                }
            }
            // 返回下载的文件内容
            return datas;
        }catch(Exception e){
            e.printStackTrace();
            return null; // 下载失败,返回null
        }
    }

    
    public static String[] uploadFile(byte[] datas, String fileName, String authName){
        try{
            // 文件上传
            // 获取文件的扩展名
            String extName = fileName.substring(fileName.lastIndexOf(".") + 1);
            // 创建文件扩展信息。扩展信息包括文件的原始名称,文件的大小,文件的上传者姓名
            NameValuePair[] metaDatas = new NameValuePair[3];
            metaDatas[0] = new NameValuePair("fileName", fileName);
            metaDatas[1] = new NameValuePair("fileSize", datas.length+"");
            metaDatas[2] = new NameValuePair("auth", authName);
            
            String[] result = storageClient.upload_file(datas, extName, metaDatas);
            // 上传成功,无异常。返回字符串数组。
            // 字符串数组长度为2。 0下标位置是 卷名|组名。 1下标位置是 文件名(目录/文件)
            // fdfs为了解决上传的文件原始名称冲突内容不冲突而覆盖的问题,存储文件的时候,会提供一个uuid文件名称。
            return result;
        }catch(Exception e){
            e.printStackTrace();
            return null; // 异常发生,返回null。代表上传失败。
        }
    }
}

3.4 编写测试代码 随意新建一个包含主方法的类。com.bjsxt.test

package com.bjsxt.test;

import com.bjsxt.utils.fdfs.FdfsFileSystemUtils;
import org.csource.common.NameValuePair;

import java.io.FileOutputStream;
import java.io.InputStream;

public class TestFdfs {
    public static void main(String[] args) throws Exception {
        upload();
    }
    public static void delete() throws  Exception {
        String groupName = "group1";
        String fileName = "M00/00/00/wKhZjF514maAar2-AAA_UVqBgzQ256.png";
        boolean flag = FdfsFileSystemUtils.deleteFile(groupName,fileName);
        System.out.println(flag ? "删除文件成功" : "删除文件失败");
    }

    // 文件下载。下载的文件保存在D盘根目录下。 文件名称是文件的原始名称
    public static void download() throws Exception {
        // 用于保存文件扩展信息的数组
        NameValuePair[] metaDatas = new NameValuePair[3];
        String groupName = "group1";
        String fileName = "M00/00/00/wKhZjF514maAar2-AAA_UVqBgzQ256.png";
        // 下载文件
        byte[] datas = FdfsFileSystemUtils.downloadFile(groupName, fileName, metaDatas);
        String localName = "";
        for(NameValuePair nvp : metaDatas){
            System.out.println(nvp.getName() + " - " + nvp.getValue());
            if(nvp.getName().equals("fileName")){
                localName = nvp.getValue();
            }
        }
        // 把下载的文件内容保存到文件中。
        FileOutputStream outputStream = new FileOutputStream("D:\" + localName);
        outputStream.write(datas);
        outputStream.flush();
        outputStream.close();
    }

    // 文件上传
    public static void upload() throws  Exception {
        // 读取文件内容
        String fileName = "1.png";
        InputStream inputStream = TestFdfs.class.getClassLoader().getResourceAsStream(fileName);
        // 创建字节数组
        byte[] datas = new byte[inputStream.available()];
        // 读取文件内容到字节数组中。
        inputStream.read(datas, 0, datas.length);
        // 上传文件
        String[] result = FdfsFileSystemUtils.uploadFile(datas, fileName, "老金");
        System.out.println("卷名:" + result[0]);
        System.out.println("文件名:" + result[1]);
        System.out.println("返回数组的长度:" + result.length);

        inputStream.close();
    }
}

1.《FastDFS》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《FastDFS》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/jiaoyu/2372244.html