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

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前