hdfs java客户端使用,文件上传下载,预览的实现

2024-06-21 11:20

本文主要是介绍hdfs java客户端使用,文件上传下载,预览的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 环境部署

       1.1 Linux hadoop集群搭建 Hadoop大数据集群搭建(超详细)_hadoop集群搭建-CSDN博客

       1.2 windows hadoop util 安装 

     Hadoop——Windows系统下Hadoop单机环境搭建_hadoop windows开发环境搭建-CSDN博客

        1.3 温馨提示,如果要使用java客户端的api,本地就必须需要安装hadoop才能调用,如果要脱离环境,可以使用WebHDFS,具体的可以搜索一下Hadoop REST API – WebHDFS

       本项目是基于java客户端api实现的

2.Maven 配置

        <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.9</version></dependency><!-- hadoop --><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.2.4</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>3.2.4</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.2.4</version></dependency>

3.hdfs java api 工具类

​
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;/*** @author maple* @describe* @createTime 2024/05/12*/
@Component
@ConditionalOnBean(FileSystem.class)
public class HadoopTemplate {private static final Logger log = LoggerFactory.getLogger(HadoopConfig.class);@Autowiredprivate FileSystem fileSystem;public void uploadFile(String srcFile, String destPath) {copyFileToHDFS(false, true, srcFile, destPath);}public void uploadFile(boolean del, String srcFile, String destPath) {copyFileToHDFS(del, true, srcFile, destPath);}public void delDir(String path) {rmdir(path, null);}public void download(String fileName, String savePath) {getFile(fileName, savePath);}/*** 创建目录** @param filePath* @param create* @return*/public boolean existDir(String filePath, boolean create) throws IOException {boolean flag = false;if (StringUtils.isEmpty(filePath)) {throw new IllegalArgumentException("filePath不能为空");}Path path = new Path(filePath);if (create) {if (!fileSystem.exists(path)) {fileSystem.mkdirs(path);}}if (fileSystem.isDirectory(path)) {flag = true;}return flag;}/*** 创建目录** @param filePath* @return*/public boolean existFile(String filePath) throws IOException {if (StringUtils.isEmpty(filePath)) {throw new IllegalArgumentException("filePath不能为空");}Path path = new Path(filePath);return fileSystem.exists(path);}/*** 文件上传至 HDFS** @param delSrc    指是否删除源文件,true 为删除,默认为 false* @param overwrite* @param srcFile   源文件,上传文件路径* @param destPath  hdfs的目的路径*/public void copyFileToHDFS(boolean delSrc, boolean overwrite, String srcFile, String destPath) {// 源文件路径是Linux下的路径,如果在 windows 下测试,需要改写为Windows下的路径,比如D://hadoop/djt/weibo.txtPath srcPath = new Path(srcFile);Path dstPath = new Path(destPath);// 实现文件上传try {// 获取FileSystem对象fileSystem.copyFromLocalFile(delSrc, overwrite, srcPath, dstPath);System.out.println(dstPath);} catch (IOException e) {log.error("", e);}}/*** 删除文件或者文件目录** @param path*/public void rmdir(String path, String fileName) {try {if (StringUtils.isNotBlank(fileName)) {path = path + "/" + fileName;}// 删除文件或者文件目录  delete(Path f) 此方法已经弃用fileSystem.delete(new Path(path), true);} catch (IllegalArgumentException | IOException e) {log.error("", e);}}/*** 从 HDFS 下载文件** @param hdfsFile* @param destPath 文件下载后,存放地址*/public void getFile(String hdfsFile, String destPath) {Path hdfsPath = new Path(hdfsFile);Path dstPath = new Path(destPath);try {// 下载hdfs上的文件fileSystem.copyToLocalFile(hdfsPath, dstPath);} catch (IOException e) {log.error("", e);}}public void writer(String destPath, InputStream in)  {try {FSDataOutputStream out = fileSystem.create(new Path(destPath));IOUtils.copyBytes(in, out, fileSystem.getConf());} catch (IOException e) {e.printStackTrace();}}public void open(String destPath, OutputStream out) {FSDataInputStream in = null;try {in = fileSystem.open(new Path(destPath));IOUtils.copyBytes(in,out,4096,false);in.seek(0);IOUtils.copyBytes(in,out,4096,false);} catch (IOException e) {e.printStackTrace();} finally {IOUtils.closeStream(in);}}public String getFileExtension(String destPath) {Path path = new Path(destPath);FileStatus fileStatus = null;try {// 获取文件的状态信息fileStatus = fileSystem.getFileStatus(path);} catch (IOException e) {log.info("获取文件的状态信息 IOException? " + e);}// 检查是否是目录boolean isDir = fileStatus.isDirectory();log.info("Is directory? " + isDir);// 检查是否是文件boolean isFile = fileStatus.isFile();log.info("Is file? " + isFile);// 如果是文件,可以获取文件的扩展名if (isFile) {String fileName = path.getName();String fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1);log.info("File extension: " + fileExtension);return fileExtension;}return "";}public static String getContentType(String destPath) throws IOException {Path hdfsPath = new Path(destPath);// 获取文件名String fileName = hdfsPath.getName();// 根据文件扩展名推断ContentType,这里只是一个简单的例子if (fileName.endsWith(".txt")) {return "text/plain";} else if (fileName.endsWith(".jpg")) {return "image/jpeg";} else if (fileName.endsWith(".png")) {return "image/png";} else {// 默认返回"application/octet-stream"return "application/octet-stream";}}//获取特定路径的所有文件public void getFileList(String path) throws IOException {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");FileStatus[] fileStatuses = fileSystem.listStatus(new Path(path));for(FileStatus fileStatus: fileStatuses) {System.out.println(fileStatus.getPath().getName());System.out.println(format.format(fileStatus.getModificationTime()));if(fileStatus.isDirectory())System.out.println("目录");elseSystem.out.println("文件");}//排序,目录放前面,文件放后面//Collator collator = Collator.getInstance(Locale.CHINA);//fileList.sort((f1, f2) -> (collator.compare(f1.getType(), f2.getType())));//return System.out.println(format.format(fileStatus.getModificationTime()));;}/*** 多文件(文件夹)** @param cloudPath*            cloudPath* @author liudz* @date 2020/6/8* @return 执行结果**/public OutputStream down(String cloudPath,ZipOutputStream zos,ByteArrayOutputStream out) {try {compress(cloudPath, zos, fileSystem);} catch (IOException e) {log.info("----error:{}----" + e.getMessage());}return out;}/*** 多文件(文件夹)** @param cloudPath*            cloudPath* @author liudz* @date 2020/6/8* @return 执行结果**/public OutputStream down2(String cloudPath) {// 1获取对象ByteArrayOutputStream out = null;try {out = new ByteArrayOutputStream();ZipOutputStream zos = new ZipOutputStream(out);compress(cloudPath, zos, fileSystem);zos.close();} catch (IOException e) {log.info("----error:{}----" + e.getMessage());}return out;}/*** compress** @param baseDir*            baseDir* @param zipOutputStream*            zipOutputStream* @param fs*            fs* @author liudz* @date 2020/6/8**/public void compress(String baseDir, ZipOutputStream zipOutputStream, FileSystem fs) throws IOException {try {FileStatus[] fileStatulist = fs.listStatus(new Path(baseDir));log.info("basedir = " + baseDir);String[] strs = baseDir.split("/");//lastName代表路径最后的单词String lastName = strs[strs.length - 1];for (int i = 0; i < fileStatulist.length; i++) {String name = fileStatulist[i].getPath().toString();name = name.substring(name.indexOf("/" + lastName));if (fileStatulist[i].isFile()) {Path path = fileStatulist[i].getPath();FSDataInputStream inputStream = fs.open(path);zipOutputStream.putNextEntry(new ZipEntry(name.substring(1)));IOUtils.copyBytes(inputStream, zipOutputStream, Integer.parseInt("1024"));inputStream.close();} else {zipOutputStream.putNextEntry(new ZipEntry(fileStatulist[i].getPath().getName() + "/"));log.info("fileStatulist[i].getPath().toString() = " + fileStatulist[i].getPath().toString());compress(fileStatulist[i].getPath().toString(), zipOutputStream, fs);}}} catch (IOException e) {log.info("----error:{}----" + e.getMessage());}}}​

 4. 配置

/*** @author maple* @describe* @createTime 2024-05-01*/
@Configuration
public class HadoopConfig {private static final Logger log = LoggerFactory.getLogger(HadoopConfig.class);@Value("${hadoop.user}")private String user;@Value("${hadoop.password}")private String password;@Value("${hdfs.hdfs-site}")private String hdfsSite;@Value("${hdfs.core-site}")private String coreSite;@Bean("fileSystem")public FileSystem createFs() throws Exception {System.setProperty("HADOOP_USER_NAME", user);System.setProperty("HADOOP_USER_PASSWORD", password);//读取配置文件org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();
//        conf.addResource(coreSite);
//        conf.addResource(hdfsSite);conf.set("fs.defaultFS",hdfsSite);conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");log.info("===============【hadoop configuration info start.】===============");log.info("【hadoop conf】: size:{}, {}", conf.size(), conf.toString());log.info("【fs.defaultFS】: {}", conf.get("fs.defaultFS"));log.info("【fs.hdfs.impl】: {}", conf.get("fs.hdfs.impl"));FileSystem fs = FileSystem.newInstance(conf);log.info("【fileSystem scheme】: {}", fs.getScheme());log.info("===============【hadoop configuration info end.】===============");return fs;}
}
hadoop:user: user001password: ******hdfs:hdfs-site: hdfs://hadoop101:9000core-site:

5.使用案例

上传文件

 /*** 通用上传请求(单个)*/@PostMapping("/upload/{parentId}")@Transactionalpublic AjaxResult uploadFile(MultipartFile file,@PathVariable Long parentId) throws Exception{try{String extension = FileUploadUtils.getExtension(file);// 上传文件路径String filePath = RuoYiConfig.getProfile();// 获取当前用户本人的存储目录DiskStorage diskStorage = diskStorageService.selectDiskStorageByUserId(SecurityUtils.getUserId());if (Objects.isNull(diskStorage)) throw new ServiceException("未初始化存储空间");if (diskStorage.getTotalCapacity()-diskStorage.getUsedCapacity()<=0) throw new ServiceException("存储空间不足");if (parentId.equals(0L)) {filePath = filePath+"/"+diskStorage.getBaseDir();} else {DiskFile parentIdFile = diskFileService.selectDiskFileById(parentId);if (Objects.isNull(parentIdFile)) throw new ServiceException("父文件夹不存在");filePath = filePath+StringUtils.substringAfter(parentIdFile.getUrl(), Constants.HADOOP_PREFIX).replace("--","/");}diskSensitiveWordService.filterSensitiveWord(file.getOriginalFilename());DiskFile diskFile = new DiskFile();String fileName = RandomUtil.randomString(4)+"_"+file.getOriginalFilename();diskFile.setName(fileName);// 上传并返回新文件名称fileName = FileUploadUtils.upload(filePath,false, file,fileName);// 上传到hdfsString descPath = StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
//把本地文件上传到hdfshadoopTemplate.copyFileToHDFS(true,true,RuoYiConfig.getProfile()+ StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX), descPath);String url = serverConfig.getUrl() + Constants.HADOOP_PREFIX + descPath.replace("/","--");diskFile.setCreateId(getUserId());diskFile.setOldName(file.getOriginalFilename());diskFile.setIsDir(0);diskFile.setOrderNum(0);diskFile.setParentId(parentId);diskFile.setUrl(url.replace(serverConfig.getUrl(),""));diskFile.setSize(file.getSize());diskFile.setType(diskFileService.getType(extension));diskFileService.save(diskFile,diskStorage);AjaxResult ajax = AjaxResult.success();ajax.put("url", url);ajax.put("fileName", url.replace(serverConfig.getUrl(),""));ajax.put("newFileName", FileUtils.getName(fileName));ajax.put("originalFilename", file.getOriginalFilename());ajax.put("size", file.getSize());ajax.put("type", extension);return ajax;}catch (Exception e){return AjaxResult.error(e.getMessage());}}

文件下载

    /*** hadoop文件下载*/@GetMapping("/download/zip")public void hadoopDownload(DownloadBo downloadBo, HttpServletResponse response) {List<DiskFile> diskFiles;String dest = RuoYiConfig.getProfile()+"/";if (StringUtils.isNotEmpty(downloadBo.getUuid())&&StringUtils.isNotEmpty(downloadBo.getSecretKey())) {diskFiles = diskFileService.selectDiskFileListByIds(Arrays.stream(downloadBo.getIds().split(",")).map(String::trim).map(Long::valueOf).toArray(Long[]::new));dest = dest + downloadBo.getUuid();} else {diskFiles = diskFileService.selectDiskFileListByIds(Arrays.stream(downloadBo.getIds().split(",")).map(String::trim).map(Long::valueOf).toArray(Long[]::new),getUserId());dest = dest + RandomUtil.randomString(6);}String downloadPath = dest + ".zip";try {ByteArrayOutputStream out = null;try {out = new ByteArrayOutputStream();ZipOutputStream zos = new ZipOutputStream(out);for (int i = 0; i < diskFiles.size(); i++) {String path = StringUtils.substringAfter(diskFiles.get(i).getUrl(),Constants.HADOOP_PREFIX);// 本地资源路径path = path.replace("--","/");//从远程下载文件到本地hadoopTemplate.down(path,zos,out);}zos.close();} catch (Exception e) {log.debug("diskfile 从远程下载文件到本地报错: "+e);}// 调用zip方法进行压缩byte[] data = out.toByteArray();out.close();response.reset();response.addHeader("Access-Control-Allow-Origin", "*");response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");response.addHeader("Content-Length", "" + data.length);response.setContentType("application/octet-stream; charset=UTF-8");IOUtils.write(data, response.getOutputStream());} catch (IOException e) {log.error("diskFile 下载文件失败", e);} finally {FileUtils.deleteFile(downloadPath);}}

文件预览

import com.ruoyi.disk.HadoopTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;import java.io.ByteArrayOutputStream;@Controller
@RequestMapping("/hadoop")
public class HadoopController {@Autowiredprivate HadoopTemplate hadoopTemplate;@Value("${hdfs.hdfs-site}")private String hdfsSite;@GetMapping("/{descPath}")public ResponseEntity<ByteArrayResource> preview(@PathVariable("descPath") String descPath) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();hadoopTemplate.open(descPath.replace("--", "/"), outputStream);String fileExtension = hadoopTemplate.getFileExtension(descPath.replace("--", "/"));byte[] byteArray = outputStream.toByteArray();// 创建字节数组资源ByteArrayResource resource = new ByteArrayResource(byteArray);// 设置响应头HttpHeaders headers = new HttpHeaders();switch (fileExtension) {case "png":headers.setContentType(MediaType.IMAGE_PNG);break;case "gif":headers.setContentType(MediaType.IMAGE_GIF);break;case "jpeg":headers.setContentType(MediaType.IMAGE_JPEG);break;default:headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);break;}// 返回字节数组资源作为响应return ResponseEntity.ok().headers(headers).contentLength(byteArray.length).body(resource);}}

6. 完整项目代码地址:netdisk: 在线网盘系统,有本存储版,和hadoop大数据hdfs分布式文件存储版本,使用了DFA算法,实现了文件夹的创建与修改,多级目录,很正常的文件夹一样,支持所有文件上传,并按文件类型分类,支持文件删除,回收站管理,恢复与彻底删除,支持公开分享和私密分享可自动生成提取码,设置过期时间或永久有效,支持图片,视频文件的预览,支持文件夹及文件的批量压缩下载

这篇关于hdfs java客户端使用,文件上传下载,预览的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1081080

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程