在前篇 高可用高性能分布式文件系统FastDFS进阶keepalived+nginx对多tracker进行高可用热备 中已介绍搭建高可用的分布式文件系统架构。

  那怎么在程序中调用,其实网上有很多栗子,这里在他们的基础上作个简单的介绍。

下载源码并加入本地仓库

官网Java客户端源代码:https://github.com/happyfish100/fastdfs-client-java

打开源码后 执行maven install 将代码打成jar到本地maven仓库(这步可自行 google)

示例源码

然后创建一个Demo工程,这里采用spring mvc模式创建。

在pom中加入引用 maven中依赖jar包

<!-- fastdfs上传下载图片 路径和上面的pom中对应 -->

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

fastdfs-client.properties

在resources的properties文件夹中创建配置文件fastdfs-client.properties

fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80fastdfs.tracker_servers = 10.0.11.201:22122,10.0.11.202:22122,10.0.11.203:22122

创建FastDFSClient工具类

package com.james.utils;import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URLDecoder;/*** Created by James on 2015/11/14.* FastDFS文件上传*/
public class FastDFSClientUtils {private TrackerClient trackerClient = null;private TrackerServer trackerServer = null;private StorageServer storageServer = null;private StorageClient1 storageClient = null;public FastDFSClientUtils(String conf) throws Exception {if (conf.contains("classpath:")) {String path = this.getClass().getResource("/").getPath();conf = conf.replace("classpath:", URLDecoder.decode(path, "UTF-8"));}ClientGlobal.init(conf);trackerClient = new TrackerClient();trackerServer = trackerClient.getConnection();storageServer = null;storageClient = new StorageClient1(trackerServer, storageServer);}/*** 上传文件方法* <p>Title: uploadFile</p>* <p>Description: </p>** @param fileName 文件全路径* @param extName  文件扩展名,不包含(.)* @param metas    文件扩展信息* @return* @throws Exception*/public String uploadFile(String fileName, String extName, NameValuePair[] metas) {String result = null;try {result = storageClient.upload_file1(fileName, extName, metas);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();}return result;}/*** 上传文件,传fileName** @param fileName 文件的磁盘路径名称 如:D:/image/aaa.jpg* @return null为失败*/public String uploadFile(String fileName) {return uploadFile(fileName, null, null);}/*** @param fileName 文件的磁盘路径名称 如:D:/image/aaa.jpg* @param extName  文件的扩展名 如 txt jpg等* @return null为失败*/public String uploadFile(String fileName, String extName) {return uploadFile(fileName, extName, null);}/*** 上传文件方法* <p>Title: uploadFile</p>* <p>Description: </p>** @param fileContent 文件的内容,字节数组* @param extName     文件扩展名* @param metas       文件扩展信息* @return* @throws Exception*/public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) {String result = null;try {result = storageClient.upload_file1(fileContent, extName, metas);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();}return result;}/*** 上传文件** @param fileContent 文件的字节数组* @return null为失败* @throws Exception*/public String uploadFile(byte[] fileContent) throws Exception {return uploadFile(fileContent, null, null);}/*** 上传文件** @param fileContent 文件的字节数组* @param extName     文件的扩展名 如 txt  jpg png 等* @return null为失败*/public String uploadFile(byte[] fileContent, String extName) {return uploadFile(fileContent, extName, null);}/*** 文件下载到磁盘** @param path   图片路径* @param output 输出流 中包含要输出到磁盘的路径* @return -1失败,0成功*/public int download_file(String path, BufferedOutputStream output) {//byte[] b = storageClient.download_file(group, path);int result = -1;try {byte[] b = storageClient.download_file1(path);try {if (b != null) {output.write(b);result = 0;}} catch (Exception e) {} //用户可能取消了下载finally {if (output != null)try {output.close();} catch (IOException e) {e.printStackTrace();}}} catch (Exception e) {e.printStackTrace();}return result;}/*** 获取文件数组** @param path 文件的路径 如group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg* @return*/public byte[] download_bytes(String path) {byte[] b = null;try {b = storageClient.download_file1(path);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();}return b;}/*** 删除文件** @param group       组名 如:group1* @param storagePath 不带组名的路径名称 如:M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg* @return -1失败,0成功*/public Integer delete_file(String group, String storagePath) {int result = -1;try {result = storageClient.delete_file(group, storagePath);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();}return result;}/*** @param storagePath 文件的全部路径 如:group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg* @return -1失败,0成功* @throws IOException* @throws Exception*/public Integer delete_file(String storagePath) {int result = -1;try {result = storageClient.delete_file1(storagePath);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();}return result;}
}

Java客户端文件上传、下载、删除和元数据获取测试:

package com.james.fdfs;
import org.junit.Test;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import  com.james.utils.FastDFSClientUtils;public class FastDFSClientUtilsTest {/*** 文件上传测试*/@Testpublic void testUpload() {File file = new File("C:\\Users\\James\\Pic\\share.jpg");Map<String,String> metaList = new HashMap<String, String>();metaList.put("width","1024");metaList.put("height","768");String fid = FastDFSClientUtils.uploadFile(file,file.getName(),metaList);System.out.println("upload local file " + file.getPath() + " ok, fileid=" + fid);//上传成功返回的文件ID: group1/M00/00/00/wKgAyVgFk9aAB8hwAA-8Q6_7tHw351.jpg}/*** 文件下载测试*/@Testpublic void testDownload() {int r = FastDFSClientUtils.download_file("group1/M00/00/00/wKgAyVgFk9aAB8hwAA-8Q6_7tHw351.jpg", new File("DownloadFile_fid.jpg"));System.out.println(r == 0 ? "下载成功" : "下载失败");}/*** 文件删除测试*/@Testpublic void testDelete() {int r = FastDFSClientUtils.delete_file("group1/M00/00/00/wKgAyVgFk9aAB8hwAA-8Q6_7tHw351.jpg");System.out.println(r == 0 ? "删除成功" : "删除失败");}
}

如果没有什么问题将会看到打印的日志。

Net版本

net版本可参考另外一位网友代码:

https://github.com/huanzui/fastdfs.client.net

问题

现在分布式文件平台已经完成了搭建和代码测试,但实践过程中还是有几个问题:

1、上传到平台的文件名都是无规律的64base编码过的字符串,因此如果只作为如图片等文件存储是没有问题的,因为我们不关心其文件名,但如果作为要下载的内容,如附件,或安装包,下载时如果还是编码那无法直观的知道此文件是做什么的,是要转换为正确的文件名。

解决:关于这个问题,网上有方法是通过nginx,利用域名和FID拼出url,然后在url后面增加一个参数,指定原始文件名。

例如:http://121.14.161.48:9030/group2/M00/00/89/eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.apk?attname=filename.apk

在Nginx上进行如下配置,这样Nginx就会截获url中的参数attname,在Http响应头里面加上字段 Content-Disposition “attachment;filename=$arg_attname”。

这里只提供了一个方案,具体内容其实还需要一个篇幅来介绍,有时间再写吧。

2、实际用的时候我们其实是想按业务还将不同文件放在不同的文件夹中的,比如聊天文件,文档文件,还有临时文件 有时需要定时清理的,但分布式文件平台是没法指定文件夹的。

解决:最常用的做法是自己实现一个文件对应库,将上传的文件名,时间,对应的业务等信息与最终的文件路径对应起来,这样就可以作任何逻辑了,但缺点是非常麻烦。

FastDFS没有看到保存到指定的2级目录的API,但可以保存到指定的group,可以指定某个group为哪个业务用。但这样会破坏整个FastDFS的分布式结构,造成某个group非常巨大,而且不容易扩容。实际使用时还会有其它业务的内容进入到此group。

3、大文件如何断点续传?

如果文件大于100M,则需要断点续传的功能了,FastDFS对于大文件来说是有点吃力的,但还是可以实现,根据网友提供的方案来看就是需要客户进行切片上传,并且切片字节大小小于等于storage配置的buff_size,默认是256k,这一块需要自己实现。

高可用高性能分布式文件系统FastDFS实践Java程序相关推荐

  1. 【FastDFS】如何打造一款高可用的分布式文件系统?这次我明白了!!

    写在前面 前面我们学习了如何基于两台服务器搭建FastDFS环境,而往往在生产环境中,需要FastDFS做到高可用,那如何基于FastDFS打造一款高可用的分布式文件系统呢?别急,今天,我们就一起来基 ...

  2. java基础巩固-宇宙第一AiYWM:为了维持生计,架构知识+分布式微服务+高并发高可用高性能知识序幕就此拉开(三:注册中心、补充CAP定理、BASE 理论)~整起

    架构知识+分布式微服务+高并发高可用高性能知识序幕就此拉开(一:总览篇) 网关开了个头 你请求来了,我网关把你拦截住,验明正身,加以控制,协助你调用服务,完成请求的调用.但是这个过程中,为了解耦和或者 ...

  3. 视频教程- 19年录制Redis实战教程 高可用秒杀分布式锁布隆过滤器实战 SpringBoot教程整合-Java

    19年录制Redis实战教程 高可用秒杀分布式锁布隆过滤器实战 SpringBoot教程整合 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有nod ...

  4. 分布式文件系统FastDFS详解-附带视频教程

    目录 1.FastDFS教程 2.FastDFS安装 安装FastDFS FastDFS配置文件详解 FastDFS启动 3.FastDFS重启与FastDFS关闭 FastDFS关闭 4.FastD ...

  5. 分布式文件系统FastDFS架构剖析

    文/余庆 FastDFS是一款类Google FS的开源分布式文件系统,它用纯C语言实现,支持Linux.FreeBSD.AIX等UNIX系统.它只能通过专有API对文件进行存取访问,不支持POSIX ...

  6. 分布式文件系统----FastDFS

    FastDFS 1.分布式文件系统 1.1 FastDFS简介 1.2 FastDFS整体架构 1.3 FastDFS的存储策略 1.4 FastDFS的上传过程 1.5 FastDFS的文件同步 1 ...

  7. (转)淘淘商城系列——分布式文件系统FastDFS

    http://blog.csdn.net/yerenyuan_pku/article/details/72801777 商品添加的实现,包括商品的类目选择,即商品属于哪个分类?还包括图片上传,对于图片 ...

  8. 唯品会、滴滴、沪江架构师,关于微服务粒度、高可用、持续交互的实践分享交流(下)...

    架构师小组交流会:每期选择一个时下最热门的技术话题进行实践经验分享. 本期小组交流会邀请到了沪江黄凯.唯品会郑明华.滴滴赵伟.七牛云肖勤,对微服务粒度.高可用.持续交互展开了交流. 本期接着上期唯品会 ...

  9. 高可用,完全分布式Hadoop集群HDFS和MapReduce安装配置指南

    原文:http://my.oschina.net/wstone/blog/365010#OSC_h3_13 (WJW)高可用,完全分布式Hadoop集群HDFS和MapReduce安装配置指南 [X] ...

最新文章

  1. Java 多线程的基本方式
  2. [译] Lenses:可组合函数式编程的 Getter 和 Setter(第十九部分)
  3. java treemap用法_JAVA作业,使用TreeMapK,V类
  4. 如何删除过期的数据库备份文件呢? .
  5. mysql al32utf8_Oracle 11g更改字符集AL32UTF8为ZHS16GBK
  6. 线性判别分析(Linear Dicriminant Analysis)参数推导记录备忘
  7. MS CRM 2011 如何向自定义Ribbon按钮传递参数
  8. 前端学习-jQuery源码学习
  9. php 处理vue上传图片 base64_encode file_put_contents file_get_contents
  10. python找到最大最小值、最大最小值的位置、删除最大值最小值
  11. Oracle 根据dbf文件的数据恢复
  12. java做一个鼠标连点_用C语言写一个鼠标连点器
  13. 学校计算机房的制度,小学计算机房管理制度
  14. Python操作Redis之mset和mget
  15. 第十六周项目3电子词典
  16. 数据库中“一对一”、“一对多”、“多对多”的判断方法
  17. YOLOV2 YOLO9000
  18. 7080mt安装linux网卡驱动,Intel英特尔PRO100/1000/10GbE系列网卡驱动
  19. 微信新增「炸屎」表情互动特效,玩上瘾了
  20. 为什么换了固态硬盘电脑会快?详解硬盘与内存的关系

热门文章

  1. boost::remove_vertex用法的测试程序
  2. boost::describe模块实现console的测试程序
  3. boost::coroutine模块实现power的测试程序
  4. boost::contract模块实现friend功能的测试程序
  5. Boost::context模块callcc的斐波那契测试程序
  6. ITK:复制复合变换CompositeTransform
  7. VTK:Rendering之DiffuseSpheres
  8. VTK:相互作用之StyleSwitch
  9. Qt Creator建立一个通用项目
  10. Qt Creator调试器故障排除