了解基础概念

什么是分布式文件系统?

全称:Distributed File System,即简称的DFS

这个东西可以是一个软件,也可以说是服务器,和tomcat差不多,即相当于软件也相当于是服务器,这个软件就是用来管理文件的

这个软件所管理的文件通常不是在一个服务器节点上,而是在多个服务器节点上

服务器节点通过网络相连构成一个庞大的文件存储服务器集群,这些服务器都用于存储文件资源,通过分布式文件系统来管理这些服务器上的文件

传统文件系统 和 分布式文件系统对比

传统文件系统

image

缺点

  • 所有的文件都存放在一台计算机中,如果这台计算机挂彩了,那么就会导致整个服务不可用( 文件不能上传和下载了 )
  • 如果这台计算机磁盘损坏了,那么会丢失所有的文件
  • 这台计算机的磁盘空间非常有限,很容易到达磁盘的上限,导致无法上传文件

回顾玩servlet时的文件上传和下载

文件上传

假如前端轰HTML写法是如下的样子:

<div id="image">
    <label for="">标题图片:</label>
    <input type="file" id="file" name="file" >
    <img src="" alt="" width="100px" height="150px">
</div>

JS写法如下:

// 当图片发生改变时		也就是用户点击file框,上传文件时
$("#file").on('change' , function() {

    // 创建一个FormData空对象,就相当于是伪造了一个form表单
    let formData = new FormData();

    // 这个FromData对象就用来装文件内容
    // 文件的files属性本质是个数组
    let files = $("#file").prop("files");
    formData.append("upFile" , files[0]);

    $.ajax({

        url: '/ajax/upload.do',
        type: 'post',
        data: formData,
        dataType: 'json',

        cache: false,    		// 上传文件不需要缓存
        contentType: false,      // 不需要对内容类型进行处理  因为内容是一个FormData对象
        processData: false,      // 不需要对数据进行处理,因为上面的data是一个FormData对象

        // 后台返回的格式 :
        // {"errno":"0" , "data":[{"alt":"1633528500498.jpg" , "url":"/upload/2021-10-06/1633528500498.jpg"}]}
        success: function (info) {
            info.data.forEach(function (data) {

                // $("#image img").remove();
                // $("#image").append('<img src=" '+data.url+' " alt="" width="100px" height="150px">')

                /*
                     注掉的这种是:html中没有img标签时使用
                     因为:使用下面这种方法的情景是 页面本来就有一个img框	即:初始页面上这个file本身有一张图片),所以下面这种可以做到图片改变时把图片的路径换掉,也就是图片渲染 即数据回填
                     但是:如果页面一开始file的位置是不应该有图片的,是后面用户选了之后才出现图片预览效果,那么:就使用注释掉的这种方法:追加
	*/

                $("#image img").attr("src" , data.url);
            });
        }
    });
})

那么后端的low代码如下:

import com.alibaba.fastjson.JSON;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;


// @MultipartConfig 文件注解
@MultipartConfig
@WebServlet("/ajax/upload.do")
public class UploadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, 
    IOException {

        /*
		 *   想要构建的是这么一个玩意儿
		 *       "errno":0 data:[{ url:"图片地址“} , {alt:"图片说明“} , {href:"null"}]
		 *
		 * */

        ArrayList<Object> list = new ArrayList<>();

        Collection<Part> parts = req.getParts();   // 这是获取前台上传的文件

        for (Part part : parts) {

            // 先构建 data:[{ } , { }]中的[{ } , { }]

            // 获取文件的全路径
            // 但是:不同浏览器的这个全路径都不一样,所以需要截取从而自定义文件名
            String filePath = part.getSubmittedFileName();  
            // System.out.println(filePath);
            // 截取文件的后缀名
            int subFileName = filePath.lastIndexOf(".");
            String fileSuffix = filePath.substring(subFileName);

            // 自己给文件重新定义一个名字,并规定存放的地方
            String timeStr = LocalDate.now().toString();

            // 获取当前项目的一个指定文件夹名字,用来保存文件 注意:getRealPath这是获取的当前项目的全路径,即:从盘符开始的路径
            String proPathName = this.getServletContext().getRealPath("/upload/" + timeStr );
            File file = new File(proPathName);
            if (!file.exists()){
                file.mkdirs();
            }

            // 拼接文件后缀名并保存文件
            long timeStamp = new Date().getTime();
            part.write(proPathName + "/" + timeStamp + fileSuffix );

            HashMap<String, String> map = new HashMap<>();
            map.put("url" , "/upload/" + timeStr + "/" + timeStamp + fileSuffix);
            map.put("alt" , timeStamp + fileSuffix);
            map.put("href" , null);
            list.add(map);
        }

        // 再构建"errno":0 data:[{url:"图片地址“} , {alt:"图片说明“} , {href:"null"}]
        HashMap<String, Object> map = new HashMap<>();
        map.put("errno", "0");
        map.put("data", list);

        resp.getWriter().print(JSON.toJSONString(map));
    }
}
image
文件下载

后端low代码如下

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

@WebServlet("/downFile")
public class downFileInClientServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 1、获取让浏览器下载的文件路径
        String FileRealPath = "D:\\JavaTrainStudy\\servlet\\out\\production\\study06-httpServletResponse\\loginbg.png";

        // 2、告知浏览器要下载的文件名是什么?
        String fileName = FileRealPath.substring(FileRealPath.lastIndexOf("\\") + 1);

        // 3、让浏览器支持文件下载
        // Content-Disposition这个就是让浏览器支持文件下载
        // URLEncoder.encode(String s , String enc) 以防文件名是中文名,设置编码格式
        resp.setHeader("Content-Disposition" , "attachment ; filename=" + URLEncoder.encode(fileName , "utf-8"));

        // 4、获取输入、输出流对象 并 把服务器中的文件输出到浏览器上
        FileInputStream fis = new FileInputStream(FileRealPath);
        ServletOutputStream os = resp.getOutputStream();

        // 创建缓冲区
        int len = 0 ;
        byte[] buffer = new byte[1024];
        while ((len = fis.read(buffer))  > 0){
            os.write(buffer , 0 , len);
        }

        // 5、关闭流管道
        if (os != null){
            os.close();
        }
        if (fis != null){
            fis.close();
        }

    }
}

分布式文件系统

image
  • 优点
    • 解决了传统方式的单点故障问题
    • 若某一个节点出现故障,则还有其他的节点可以用来读取和写入文件
    • 提供数据备份从而避免磁盘损坏而导致的文件丢失
    • 提供扩容机制,无限增加文件存放的空间上限

认识FastDFS

常见的分布式文件系统

  • FastDFS、GFS、HDFS、Lustre 、Ceph 、GridFS 、mogileFS、TFS

了解FastDFS

官网:https://github.com/happyfish100/fastdfs

FastDFS是一个开源的轻量级分布式文件系统,为互联网应用量身定做,简单、灵活、高效,采用C语言开发,由阿里巴巴开发并开源

FastDFS对文件进行管理,功能包括:文件存储、文件同步(文件系统 和 数据备份之间的同步)、文件上传、文件下载、文件删除等

FastDFS解决了大容量文件存储的问题

FastDFS特别适合以文件为载体的在线服务,如相册网站、文档网站、图片网站、视频网站等

FastDFS充分考虑了冗余备份、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务

冗余备份:指的是文件系统中存的文件 和 数据备份中存的文件完全一致的问题

image

线性扩容:文件系统 和 数据备份不断增加呗(就是上图中再加几份嘛),和水平扩容类似

FastDFS的组成结构

由两大部分构成,一个是客户端,一个是服务端

客户端:指我们的程序,比如我们的Java程序去连接FastDFS、操作FastDFS,那我们的Java程序就是一个客户端。FastDFS提供专有API访问,目前提供了C、Java和PHP几种编程语言的API,用来访问FastDFS文件系统

服务端由两个部分构成:一个是跟踪器(tracker),一个是存储节点(storage)

  • 跟踪器 tracker:这玩意儿类似于Erueka / zookeeper注册中心,起到一个调度的作用。它是在内存中记录集群中存储节点storage的状态信息,是前端Client和后端存储节点storage的枢纽,因为相关信息全部在内存中,Tracker server的性能非常高,一个较大的集群(比如上百个group,group指的就是:文件系统 和 数据备份的组合,这二者就是一个group)中有3台就足够了
  • 存储节点 storage:用于存储文件,包括文件和文件属性(meta data,如:文件名、文件大小、文件后缀...)都保存到存储服务器磁盘上。以及完成文件管理的所有功能:文件存储、文件同步和提供文件访问(上传、下载、删除)等

开始玩FastDFS

安装FastDFS

提示

我的系统是centos 7

1、安装需要的依赖环境 gcc、libevent、libevent-devel

yum install gcc libevent libevent-devel -y

2、安装公共函数库libfastcommon 和 fastDFS压缩包

自行去前面官网中进行下载,当然:官网的wiki中有在线拉取命令

解压编译公共函数库libfastcommon

tar -zxvf libfastcommon-1.0.36.tar.gz

# 进入libfastcommon,执行里面的make.sh,编译公共函数

./make.sh 

# 当然:可以把命令进行合并 执行如下命名 就是编译并安装
./make.sh && ./make.sh install

3、安装公共函数

./make.sh install

4、解压缩fastdfs-5.11.tar.gz压缩包

tar -zxvf fastdfs-5.11.tar.gz


# 进入解压目录,编译
./make.sh

# 一样的可以用组合命令 即:编译并安装
./make.sh && ./make.sh install

检查是否安装成功,进入如下的目录即可

cd /usr/bin

往后找,出现这些fdfs开头的文件就表示成功(这些文件就是fastDFS的相关命令)

fastDFS配置文件所在地,进入如下目录即可。想要让fastDFS的配置文件生效,那么就需要放到下面的这个目录中

cd /etc/fdfs
image

拷贝两个配置文件到etc/fdfs中,这两个配置文件在解压的fastDFS的conf中,一个叫http.conf,一个叫mime.types

# 供nginx访问使用
cp http.conf /etc/fdfs

# 供nginx访问使用
cp mime.types /etc/fdfs

启动FastDFS

这玩意儿不可以直接启动,因为默认的配置文件中有一些关于文件目录的配置是不存在的,因此:只要直接启动就会报错

修改配置文件

要修改的文件就两个

image

以防万一,因此:将上面的文件拷贝一份

/etc/fdfs

mv storage.conf.sample ./storage.conf

mv tracker.conf.sample ./tracker.conf

修改tracker.conf

在这个配置文件中有一个base_path配置,指向的是fastDFS作者余庆的地址,而我们自己的linux中并没有这个目录,因此:做修改

vim tracker.conf

# 搜索此配置
/base_path

# 改成的值,也可以自定义自己的目录	注意:需要保证这个目录必须存在,没存在那就需要创建
base_path=/opt/fastdfs/tracker

修改storage.conf

需要改的内容如下

# storage存储数据目录
base_path=/opt/fastdfs/storage

# 真正存放文件的目录
store_path0=/opt/fastdfs/storage/files

# 注册当前存储节点的跟踪器地址
tracker_server=服务器ip:22122

注意:要是前面的那三个目录没有的话,记得创建,若指向的是已经创建好的目录,那就不用创建了

mkdir -p /opt/fastdfs/tracker

mkdir -p /opt/fastdfs/storage

mkdir -p /opt/fastdfs/storage/files

开启fastDFS

在任意目录下,执行如下的命令即可

# 启动tracker 要想看fdfs_trackerd的命令用法,那直接输入fdfs_trackerd就可以弹出其用法了
# 如:要关闭tracker,则命令为:fdfs_trackerd /etc/fdfs/tracker.conf stop
# 开启 | 重启就是把stop改成start | restart即可
fdfs_trackerd /etc/fdfs/tracker.conf


# 启动storage 同样的,看命令用户就直接输入fdfs_storaged
fdfs_storaged /etc/fdfs/storage.conf

查看是否启动成功

ps -ef | grep fdfs

如下图表示启动成功

image

但是上面的启动会有坑儿,所以需要确认一把

# 查看日志文件是否有报ERROR
cd /opt/fastdfs/storage/logs/storage.log

若是发现日志中报的是如下信息

ERROR - file: storage_ip_changed_dealer.c, line: 180, connect to tracker server 服务器ip:22122 fail, errno: 110, error info: Connection timed out

# 即:链接超时

这种情况一般都是22122端口没开放

# 开放22122端口
firewall-cmd --zone=public --add-port=22122/tcp --permanent

# 重启防火墙
systemctl restart firewalld.service

查看默认创建的文件数

进入如下的目录

cd /opt/fastdfs/storage/files/data
image

这里面有526个文件夹,而每一个文件夹里面又有526个文件夹,即256 * 256个文件夹,总的文件夹数目为6万多个

这256 * 256个文件夹的作用:解决的就是如下的问题

image

而fastDFS就是使用那256 * 256个文件夹,把文件分别放入那些文件夹中,这样就让搜索变得方便了

测试FastDFS

测试上传文件

要能进行测试的话,需要修改一个配置文件,因为这个配置文件中的配置信息是作者余庆的

image

要修改的内容如下

# 注意:这个目录也要保证存在,不存在就是创建 mkdir -p /opt/fastdfs/client
base_path=/opt/fastdfs/client

tracker_server=自己服务器ip:22122

搞一个用来测试上传的文件

image

执行文件上传命令

可以使用如下命令看一下测试文件上传命令是怎么写的

fdfs_test
image

提取出测试命令语法

fdfs_test <config_file> <operation>
	operation: upload, download, getmeta, setmeta, delete and query_servers
# <> 表示必填

# 因此:在测试中,文件上传的指令为:
fdfs_test /etc/fdfs/client.conf upload /root/hello-fastdfs.txt

注意:防火墙的问题啊,要是报:connect to 162.14.66.60:23000 fail, errno: 113, error info: No route to host,这就是防火墙没开放23000端口,打开就可以了

# 开放23000端口
firewall-cmd --zone=public --add-port=23000/tcp --permanent

# 刷新防火墙
systemctl restart firewalld.service

上面成功之后有一堆信息,很重要

This is FastDFS client test program v5.11

Copyright (C) 2008, Happy Fish / YuQing

FastDFS may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDFS source kit.

# 这个是说访问fastdfs的主页网址 - 目前还不能访问,需要后面弄
Please visit the FastDFS Home Page http://www.csource.org/ 
for more detail.

# 这是配置的client.conf中的信息
[2022-06-01 10:17:07] DEBUG - base_path=/opt/fastdfs/client, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0

tracker_query_storage_store_list_without_group: 
	server 1. group_name=, ip_addr=162.14.66.60, port=23000

group_name=group1, ip_addr=162.14.66.60, port=23000
storage_upload_by_filename
# 重要的信息在这里group_name、remote_filename
# group_name就是组名,在前面配置中见过它,就是说的文件系统 和 数据备份这二者的组合名
# remote_filename 远程文件名 这是关键中的关键,告知你:文件保存到那里去了
group_name=group1, remote_filename=M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt
source ip address: 10.0.0.16
file timestamp=2022-06-01 10:17:07
file size=641
file crc32=1141168436
# 这就是可以在浏览器访问这个文件的路径,但是:现在还无法访问,因为还没有配置nginx
example file url: http://162.14.66.60/group1/M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt
storage_upload_slave_by_filename
group_name=group1, remote_filename=M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt
source ip address: 10.0.0.16
file timestamp=2022-06-01 10:17:07
file size=641
file crc32=1141168436
example file url: http://162.14.66.60/group1/M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt

单独说明:remote_filename

remote_filename=M00/00/00/

M00 指的是:/opt/fastdfs/storage/files/data	就是前面去看默认创建文件数(256 * 256)的位置,跟前面的配置有关啊

00/00/ 指的就是:/opt/fastdfs/storage/files/data目录下的00子目录,这里面的00目录

CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt  指的是:保存的文件名  fastdfs会重新生成文件名,以防的就是同名文件,造成附件覆盖的问题
image image

上图中几个文件解读

# _big 就是数据备份文件
# ——m 就是meta data文件,即:文件属性文件( 文件名、文件后缀、文件大小..... )
-rw-r--r-- 1 root root 641 Jun  1 10:17 CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt
-rw-r--r-- 1 root root  49 Jun  1 10:17 CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt-m

# 这两个就是文件系统中的文件
-rw-r--r-- 1 root root 641 Jun  1 10:17 CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt
-rw-r--r-- 1 root root  49 Jun  1 10:17 CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt-m


# CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt 和 文件系统中的CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt存的内容是一样的

# CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt-m 和 CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt-m这两个备份文件也是相应的
image

测试文件下载和删除

前面已经见过对应的语法了

fdfs_test <config_file> <operation>
	operation: upload, download, getmeta, setmeta, delete and query_servers
# <> 表示必填

变一下就可以了

# 变成下载的命令,然后使用此命令查看完整命令即可
fdfs_test /etc/fdfs/client.conf download


# 根据执行上面的命令,得到文件下载的语法
fdfs_test <config_file> download <group_name> <remote_filename>

# 那么想要下载刚刚上传的文件,执行如下的命令即可
fdfs_test /etc/fdfs/client.conf download group1 M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt
# 其中:group 和 remote_filename都在前面上传时见过了
# 注:这个下载是下载到当前所在目录的位置


# 同理:就可以得到文件删除的命令了
fdfs_test /etc/fdfs/client.conf delete group1 M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt

以上这些fdfs_test只会在测试时使用,其他地方基本上都不用的

安装Nginx

上传fastdfs-niginx扩展模块 并 解压。使用官网中wiki说明的命令拉取也行

安装nginx,要是有的话就跳过

注意点:nginxfastdfs-nginx放到/usr/local目录下,不然可能会出现莫名其妙的问题

记住两个目录

# nginx安装目录
/usr/local/nginx_fdfs

# fastdfs-nginx模块的src目录
/usr/local/fastdfs-nginx-module-master/src

进入nginx安装目录,进行模块添加配置

# 进入nginx安装目录
cd nginx_fdfs

# 执行模块配置 
# prefix 就是前面让记住的nginx安装目录	add-module就是fastdfs-nginx模块的src目录
./configure --prefix=/usr/local/nginx_fdfs --add-module=/usr/local/fastdfs-nginx-module-master/src

Nginx的安装需要Linux安装相关的几个库,否则编译会出现错误,有这几个的话就不安装了

yum install gcc openssl openssl-devel pcre pcre-devel zlib zlib-devel –y

编译并安装

# 在安装的nginx目录下载执行下述命令
make & make install

修改需要的配置文件

将fastdfs-nginx扩展模块中的mod_fastdfs.conf文件复制到/etc/fdfs

cp /usr/local/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs

修改/etc/fdfs/mod_fastdfs.conf

vim mod_fastdfs.conf

# 修改内容如下:
# 这个目录要保证存在,不存在就要配置好了创建它 mkdir -p /opt/fastdfs/nginx_mod
base_path=/opt/fastdfs/nginx_mod

tracker_server=自己服务器ip:22122

# 访问地址是否带上组名
url_have_group_name = true

store_path0=/opt/fastdfs/storage/files

上面base_path目录要是不存在记得创建

进入nginx_fdfs的安装目录中,去nginx.conf中配置fastdfs-nginx的扩展模块

# 编辑nginx.conf文件
vim /usr/local/nginx_fdfs/conf/nginx.conf

# 配置内容
location ~ /group[1-9]/M0[0-9] {	
     ngx_fastdfs_module;  
}


# 解读:ngx_fastdfs_module
# 	这个指令不是Nginx本身提供的,是扩展模块提供的,根据这个指令找到FastDFS提供的Nginx模块配置文件,然后找到Tracker,最终找到Stroager

启动Nginx

/usr/local/nginx_fdfs/sbin/nginx -c /usr/local/nginx_fdfs/conf/nginx.conf  -t

/usr/local/nginx_fdfs/sbin/nginx -c /usr/local/nginx_fdfs/conf/nginx.conf

# 保险起见,查看nginx是否启动成功
ps -ef | grep nginx
image

注意:这里很容易出现启动不起来,如果下面这个进程没有启动起来

nobody    3895  3894  0 15:45 ?        00:00:00 nginx: worker process

那么:就去查看日志文件

cd /usr/local/nginx_fdfs/logs


# 还有一份日志中也可能出现错误信息
cd /opt/fastdfs/nginx_mod

现在就可以去浏览器中查看刚刚上传的文件的。注意开放端口啊

# 开放80端口
firewall-cmd --zone=public --add-port=80/tcp --permanent

# 重启防火墙
systemctl restart firewalld.service

访问前面上传文件时的url地址

This is FastDFS client test program v5.11

Copyright (C) 2008, Happy Fish / YuQing

FastDFS may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDFS source kit.

# 这个是说访问fastdfs的主页网址 - 目前还不能访问,需要后面弄
Please visit the FastDFS Home Page http://www.csource.org/ 
for more detail.

# 这是配置的client.conf中的信息
[2022-06-01 10:17:07] DEBUG - base_path=/opt/fastdfs/client, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0

tracker_query_storage_store_list_without_group: 
	server 1. group_name=, ip_addr=162.14.66.60, port=23000

group_name=group1, ip_addr=162.14.66.60, port=23000
storage_upload_by_filename
# 重要的信息在这里group_name、remote_filename
# group_name就是组名,在前面配置中见过它,就是说的文件系统 和 数据备份这二者的组合名
# remote_filename 远程文件名 这是关键中的关键,告知你:文件保存到那里去了
group_name=group1, remote_filename=M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt
source ip address: 10.0.0.16
file timestamp=2022-06-01 10:17:07
file size=641
file crc32=1141168436
# 这就是可以在浏览器访问这个文件的路径,但是:现在还无法访问,因为还没有配置nginx
example file url: http://162.14.66.60/group1/M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt
storage_upload_slave_by_filename
group_name=group1, remote_filename=M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt
source ip address: 10.0.0.16
file timestamp=2022-06-01 10:17:07
file size=641
file crc32=1141168436
example file url: http://162.14.66.60/group1/M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590_big.txt

访问:http://162.14.66.60/group1/M00/00/00/CgAAEGKWzCOACGE1AAACgUQE2TQ590.txt

扩展模块执行流程

下面这个流程很重要,涉及到后面的知识

image

Java操作FastDFS

依赖

<dependency>
    <groupId>net.oschina.zcx7878</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27.0.0</version>
</dependency>

这个是可以从阿里仓库拉取的依赖,但是严格来说这不是作者的,但是不妨碍使用

真正的依赖没有放到中央仓库中去,因此并不能通过maven拉取,而是需要去官网https://github.com/happyfish100/fastdfs-client-java/tags中下载源码,然后解压,进入解压目录,使用DOS窗口,执行mvn clean install命令,打成j本地ar包,然后就可以在maven中使用了,最后打出来的jar包是在org.csource目录下,所以正规依赖应该是下面这个

<dependency>
    <groupId>org.csource</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27-RELEASE</version>
</dependency>
image

文件上传

1、在resources目录下创建fastdfs.conf文件,并编写如下内容

tracker_server=服务器ip:22122
  • 编写文件上传代码
import org.csource.common.MyException;
import org.csource.fastdfs.*;

import java.io.IOException;

/**
 * @author : ZiXieQing
 * @version : V1.0.0
 * @className : UploadFile
 * @description : 该类功能 FastDFS文件上传
 * @packageName : com.zixieqing
 */

public class UploadFile {

    public static void main(String[] args) {

        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        try {
            // 1、初始化配置文件
            ClientGlobal.init("fastdfs.conf");

            // 2、创建tracker客户端
            TrackerClient trackerClient = new TrackerClient();
            // 3、获取trackerServer
            trackerServer = trackerClient.getConnection();
            // 4、获取storageServer
            storageServer = trackerClient.getStoreStorage(trackerServer);

            // 5、创建storage客户端 - 这个对象就是用来上传文件、下载文件、删除文件的
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);

            // 6、上传文件
            /*
                这里有两个API需要了解
                    String[] upload_file(byte[] file_buff, int offset, int length, String file_ext_name, NameValuePair[] meta_list)
                    这个API常用来web中上传文件的
                        参数1 file_buff、文件字节
                        offset、length、从文件的那个位置开始上传,截止位置
                        参数4 file_ext_name、文件后缀
                        参数5 meta_list、文件的属性文件

                    String[] upload_file(String local_filename, String file_ext_name, NameValuePair[] meta_list)
                    这个API是上传本地文件的
                        参数1 local_filename、本地文件的绝对路径
                        参数2 file_ext_name、文件后缀名
                        参数3 meta_list、文件的属性文件,linux1中的哪个meta data,一般都不传
                        
                上述这两个API,注意返回值,这个String[] 很重要,就是涉及到linux中的那个组名group 和 远程文件名remote_filename
             */
            String[] result = storageClient.upload_file("C:\\Users\\ZiXieQing\\Desktop\\图库\\19.jpg", "jpg", null);
            
            // 7、验证一下
            for (String data : result) {
                System.out.println("data = " + data);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (MyException e) {
            throw new RuntimeException(e);
        } finally {
            // 8、释放资源
            if (storageServer != null) {
                try {
                    storageServer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (trackerServer != null) {
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

浏览器访问

image

文件下载

把前面的文件上传代码改一下即可,换成另一个API而已

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

import java.io.IOException;

/**
 * @author : ZiXieQing
 * @version : V1.0.0
 * @className : DownloadFile
 * @description : 该类功能 fastDFS文件下载
 * @packageName : com.zixieqing
 */

public class DownloadFile {

    public static void main(String[] args) {

        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        try {
            // 1、初始化配置文件
            ClientGlobal.init("fastdfs.conf");

            // 2、获取tracker客户端
            TrackerClient trackerClient = new TrackerClient();
            // 3、获取trackerServer
            trackerServer = trackerClient.getConnection();
            // 4、获取storageServer
            storageServer = trackerClient.getStoreStorage(trackerServer);

            // 5、创建storage客户端
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);

            // 6、下载文件
            /*
                这里需要知道两个API
                     byte[] download_file(String group_name, String remote_filename)
                     这个API常用于web操作

                    int download_file(String group_name, String remote_filename, String local_filename)
                    这个API是把文件下载到本地磁盘中
                    这个API的返回值结果很重要
             */
            String group = "group1";
            String remoteFileName = "M00/00/00/CgAAEGKYRg-AAIrWAAD8cA4U6dY771.jpg";
            // 存入本地磁盘路径+存入磁盘的文件名
            String localFileName = "d:/靓妹.jpg";
            // 只有返回值是0才表示下载成功,否则只要是其他数字都是下载失败(其他数字有可能是组名错了,远程文件名错了........
            int result = storageClient.download_file(group, remoteFileName, localFileName);

            // 7、验证
            System.out.println("result = " + result);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (MyException e) {
            throw new RuntimeException(e);
        } finally {
            // 8、释放资源
            if (storageServer != null) {
                try {
                    storageServer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (trackerServer != null) {
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

image

文件删除

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

import java.io.IOException;

/**
 * @author : ZiXieQing
 * @version : V1.0.0
 * @className : DeleteFile
 * @description : 该类功能 FastDFS删除文件
 * @packageName : com.zixieqing
 */

public class DeleteFile {

    public static void main(String[] args) {

        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        try {
            // 1、初始化配置文件
            ClientGlobal.init("fastdfs.conf");

            // 2、获取tracker客户端
            TrackerClient trackerClient = new TrackerClient();
            // 3、获取trackerServer
            trackerServer = trackerClient.getConnection();
            // 4、获取storageServer
            storageServer = trackerClient.getStoreStorage(trackerServer);
            // 5、获取storage客户端
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);

            // 6、执行文件删除
            /*
                int delete_file(String group_name, String remote_filename)
                参数1 group_name、组名
                参数2 remote_filename、远程文件名
             */
            // 一样的,返回值是0就表示成功,其他都是删除失败
            int result = storageClient.delete_file("group", "M00/00/00/CgAAEGKYRg-AAIrWAAD8cA4U6dY771.jpg");

            // 7、验证一下
            System.out.println("result = " + result);

        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (MyException e) {
            throw new RuntimeException(e);
        }finally {
            // 8、释放资源
            if (storageServer != null) {
                try {
                    storageServer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (trackerServer != null) {
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

对应md文档

链接:FastDFS文档

posted on 2022-06-05 17:30  紫邪情  阅读(1024)  评论(2编辑  收藏  举报