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

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

大家好,又见面了,我是全栈君。

  在前篇 高可用高性能分布式文件系统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 = 80

fastdfs.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 { /** * 文件上传测试 */ @Test public 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  } /** * 文件下载测试 */ @Test public 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 ? "下载成功" : "下载失败"); } /** * 文件删除测试 */ @Test public 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,这一块需要自己实现。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/107741.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Mysql 添加字段或者创建表SQL语句「建议收藏」

    Mysql 添加字段或者创建表SQL语句「建议收藏」最近要向测试和运维发SQL脚本,习惯了用工具,忘记了原始操作手法

    2022年10月10日
  • pycharm最新2021年激活码_通用破解码

    pycharm最新2021年激活码_通用破解码,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • Crontab定时任务配置

    Crontab定时任务配置一、开启crontab1.查看crontab是否启动sudolaunchctllist|grepcron2.检查需要的文件ls-al/etc/crontab3.如果crontab文件不存在则创建sudotouch/etc/crontab上述操作完成之后就可以正常使用crontab啦二、crontab服务开启、关闭1.开启su…

    2022年10月22日
  • 基于Tess4j的图片识别

    基于Tess4j的图片识别Tess4J是对TesseractOCRAPI的JavaJNA封装。tesseract是跨平台的OCR(OpticalCharacterRecognition,光学字符识别)引擎,让开发者非常容易的集成OCR能力到他们自己的应用。通过强大的API从图片中识别和提取文本内容。Tess4J支持主流的图片格式,如TIFF,JPEG,GIF,PNG,BMP,andPDF。…

  • java maven 配置环境变量_maven 环境变量的配置详解

    java maven 配置环境变量_maven 环境变量的配置详解我的电脑是win10_64位的。一、安装,我使用的是免安装版的,直接解压缩就可以使用。二、配置环境变量。1.打开环境变量配置。右键计算机→属性→高级系统设置→高级→环境变量,在系统变量中配置。2.配置MAVEN_HOME。在系统变量中新建,变量名MAVEN_HOME,变量值,maven文件夹路径,我的路径是F:\Wab\资料\maven\资料\apache-maven-3.2.3,最好不要有中…

  • JVM – 内存模型

    JVM – 内存模型JVM-内存模型

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号