发布时间:2025-12-10 19:24:36 浏览次数:11
FastDFS(分布式文件系统)一、架构架构图:Client:客户端。使用java语言编写的项目属于客户端。TrackerServer:跟踪服务器,主要做调度工作,在访问上起负载均衡的作用。在内存中记录集群中group和storageserver的状态信息,是连接Client和Storageserver的枢纽。StorageServer:存储服务器,文件和文件属性(metadata)都保存到存储服务器上架构解读:只有两个角色,trackerserver和storageserver,不需要存储文件索引信息。
Tracker:标准服务端口22122、HTTP端口8080
Storage:标准服务端口23000、HTTP端口8888
架构图:
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.2 文件下载时序图
1.3 文件删除时序图
2.1 上传流程说明
客户端访问Tracker Tracker 返回Storage的ip和端口 客户端直接访问Storage,把文件内容和元数据发送过去。 Storage返回文件存储id。包含了组名和文件名2.2 下载流程说明
client询问tracker下载文件的storage,参数为文件标识(组名和文件名); tracker返回一台可用的storage; client直接和storage通讯完成文件下载。3.1 添加依赖
<dependencies> <!-- fdfs java客户端依赖 --> <dependency> <groupId>cn.bestwu</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> </dependencies> 是否还在为Ide开发工具频繁失效而烦恼,来吧关注以下公众号获取最新激活方式。亲测可用!
【正版授权,激活自己账号】:Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】:官方授权 正版激活 自己使用,支持Jetbrains家族下所有IDE…
3.2 编写配置文件
文件名:fdfs_client.conf
修改成自己的tracker服务器ip
connect_timeout = 10network_timeout = 30charset = UTF-8http.tracker_http_port = 8080tracker_server = 192.168.14.129:22122 3.3 导入工具类
在com.wyy.utils.fdfs.FdfsFileSystemUtils下粘贴配置工具类
package com.wyy.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);}}/** * 文件删除,FastDFS会自动删除这个文件对应的metaData。就是文件名-m这个文件。 */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;}}/** * 文件下载 * @param metaDatas - 传入一个数组,用于保存下载文件的扩展信息。如果传入null,则不需要文件扩展信息。 * 如果传入的数组不是null,则需要文件的扩展信息。 * @return 下载的文件内容 */public static byte[] downloadFile(String groupName, String fileName, NameValuePair[] metaDatas){ try{ /* * byte[] storageClient.download_file(String groupName, String fileName); * groupName - 卷名 | 组名 * fileName - 文件名,是文件保存在fdfs中的目录和文件名。 */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}}/** * 使用StorageClient对象,实现文件的上传。 */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[] storageClient.upload_file(byte[] datas, String extName, NameValuePair[] metaDatas) * datas - 要上传的文件的内容 * extName - 上传的文件的扩展名 * metaDatas - 上传的文件的扩展信息是什么。 如:文件的原始名称、文件的容量大小、文件的上传者等。 */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.wyy.test
package com.wyy.test;import com.wyy.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();}}