天天看點

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稱為存儲伺服器

FastDFS之檔案上傳/下載下傳/删除

2、檔案上傳流程

FastDFS之檔案上傳/下載下傳/删除

用戶端上傳檔案後存儲伺服器将檔案 ID 傳回給用戶端,此檔案 ID 用于以後通路該檔案的索引資訊。檔案索引資訊包括:組名,虛拟磁盤路徑,資料兩級目錄,檔案名

FastDFS之檔案上傳/下載下傳/删除

組名:檔案上傳後所在的 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);
    }
}
           

繼續閱讀