脚本宝典收集整理的这篇文章主要介绍了分布式文件系统FastDFS 技术整理,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
传统文件系统
回顾玩servlet时的文件上传和下载
文件上传
<div id="image">
<label for="">标题图片:</label>
<input type="file" id="file" name="file" >
<img src="" alt="" width="100px" height="150px">
</div>
// 当图片发生改变时 —— 也就是用户点击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 );
});
}
} );
})
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) );
}
}
文件下载
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();
}
}
}
分布式文件系统
补充:常见的分布式文件系统
注:我的系统是centos 7
安装需要的依赖环境 gcc、libevent、libevent-devel
yum install gcc libevent libevent-devel -y
tar -zxvf libfastcommon-1.0.36.tar.gz
./make.sh
# 当然:可以把命令进行合并 执行如下命令 就是编译并安装
./make.sh && ./make.sh install
./make.sh install
fastdfs-5.11.tar.gz
压缩包tar -zxvf fastdfs-5.11.tar.gz
make sh
进行编译./make.sh
# 一样的可以用组合命令 即:编译并安装
./make.sh && ./make.sh install
./make.sh install
cd /usr/bin
cd /etc/fdfs
etc/fdfs
中,这两个配置文件在解压的fastDFS的conf中,一个叫http.conf
,一个叫mime.types
# 供nginx访问使用
cp http.conf /etc/fdfs
# 供nginx访问使用
cp mime.types /etc/fdfs
/etc/fdfs
mv storage.conf.sample ./storage.conf
mv tracker.conf.sample ./tracker.conf
base_path
配置,指向的是fastDFS作者余庆的地址,而我们自己的linux中并没有这个目录,因此:做修改vim tracker.conf
# 搜索此配置
/base_path
# 改成的值,也可以自定义自己的目录( 注意:需要保证这个目录必须存在,没存在那就需要创建 )
base_path=/opt/fastdfs/tracker
# 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
# 启动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 /etc/fdfs/storage.conf
ps -ef | grep fdfs
# 查看日志文件是否有报ERROR
cat /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端口
firewall-cmd --zone=public --add-port=22122/tcp --permanent
# 重启防火墙
systemctl restart firewalld.service
# 当然:要是云服务器的话,直接在web管理界面中添加规则( 开放22122端口 ) 即可
cd /opt/fastdfs/storage/files/data
这里面有256个文件夹,而每一个文件夹里面又有256个文件夹,即256 * 256个文件夹,总的文件夹数目为6万多个
# 注意:这个目录也要保证存在,不存在就是创建 mkdir -p /opt/fastdfs/client
base_path=/opt/fastdfs/client
tracker_server=自己服务器ip:22122
执行文件上传命令
可以使用如下命令看一下测试文件上传命令是怎么写的
fdfs_test
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 xxx.xx.xx.xx: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
# 下面这个URL地址很重要,就是去浏览器访问上传的这个文件资源的地址,但是:目前还不可以访问,因为没有配置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会重新生成文件名,以防的就是同名文件,造成附件覆盖的问题
# _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这两个备份文件也是相应的
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
只会在测试时使用,其他地方基本上都不用的上传fastdfs-niginx
扩展模块 并 解压 - 使用官网中wiki说明的命令拉取也行
安装nginx,要是有的话就跳过
# nginx安装目录
/usr/local/nginx_fdfs
# fastdfs-nginx模块的src目录
/usr/local/fastdfs-nginx-module-master/src
# 进入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目录下载执行下述命令
make & make install
yum install gcc openssl openssl-devel pcre pcre-devel zlib zlib-devel –y
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
nobody 3895 3894 0 15:45 ? 00:00:00 nginx: worker process
cd /usr/local/nginx_fdfs/logs
# 还有一份日志中也可能出现错误信息
cd /opt/fastdfs/nginx_mod
resources
目录下创建fastdfs.conf
文件,并编写如下内容:tracker_server=服务器ip:22122
package com.zixieqing;
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,这个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);
}
}
}
}
}
package com.zixieqing;
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);
}
}
}
}
}
package com.zixieqing;
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);
}
}
}
}
}
以上是脚本宝典为你收集整理的分布式文件系统FastDFS 技术整理全部内容,希望文章能够帮你解决分布式文件系统FastDFS 技术整理所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。