如何将HDFS中的Zip文件复制到SFTP服务器?遇目录报错求解决
问题分析与解决方案
核心问题
你HDFS路径下的FileName.zip不是真实的Zip文件,而是一个Hadoop任务输出的目录(从_SUCCESS、part-0000000.txt这类文件就能判断,这是MapReduce/Spark任务输出的典型目录结构)。当你试图把它当作普通文件用InputStream读取时,就会触发"Is a directory"的错误。
解决方案
1. 先确认HDFS路径的真实类型
执行HDFS命令验证:
hdfs dfs -ls /path/to/FileName.zip
如果输出开头是drwxr-xr-x,说明这确实是目录而非文件。
2. 方案一:把HDFS目录打包成真实Zip后上传(推荐)
如果需要上传的是完整的Zip文件,有两种实现方式:
- 集群端命令打包
先把HDFS目录拉到本地节点,再打包成Zip,最后上传到SFTP:# 拉取HDFS目录到本地临时路径 hdfs dfs -get /path/to/FileName.zip /local/temp/ # 进入目录并打包 cd /local/temp/FileName.zip zip -r /local/temp/RealFileName.zip . # 直接从本地传到SFTP(用sftp命令) sftp user@sftp-server <<EOF put /local/temp/RealFileName.zip /sftp/dest/path/ EOF - Java代码内打包成Zip流上传
直接在代码里遍历HDFS目录文件,生成Zip流后传给ChannelSftp:Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(conf); Path hdfsDirPath = new Path("/path/to/FileName.zip"); // 构建Zip输出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zipOut = new ZipOutputStream(baos); // 遍历HDFS目录下的文件 RemoteIterator<LocatedFileStatus> fileIterator = fs.listFiles(hdfsDirPath, false); while (fileIterator.hasNext()) { LocatedFileStatus fileStatus = fileIterator.next(); Path filePath = fileStatus.getPath(); String fileName = filePath.getName(); // 可选:跳过_SUCCESS文件 if (fileName.equals("_SUCCESS")) continue; ZipEntry zipEntry = new ZipEntry(fileName); zipOut.putNextEntry(zipEntry); // 读取HDFS文件内容写入Zip流 InputStream in = fs.open(filePath); IOUtils.copy(in, zipOut); in.close(); zipOut.closeEntry(); } zipOut.close(); // 上传Zip流到SFTP ChannelSftp sftp = ...; // 已初始化的ChannelSftp实例 sftp.put(new ByteArrayInputStream(baos.toByteArray()), "/sftp/dest/RealFileName.zip");
3. 方案二:直接上传目录内的所有文件到SFTP
如果不需要打包成Zip,可直接把目录里的文件逐个传到SFTP对应目录:
Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(conf); Path hdfsDirPath = new Path("/path/to/FileName.zip"); String sftpDestDir = "/sftp/dest/FileName/"; // 创建SFTP目标目录 sftp.mkdir(sftpDestDir); // 遍历并上传文件 RemoteIterator<LocatedFileStatus> fileIterator = fs.listFiles(hdfsDirPath, false); while (fileIterator.hasNext()) { LocatedFileStatus fileStatus = fileIterator.next(); Path filePath = fileStatus.getPath(); String fileName = filePath.getName(); // 可选:跳过_SUCCESS文件 if (fileName.equals("_SUCCESS")) continue; InputStream in = fs.open(filePath); sftp.put(in, sftpDestDir + fileName); in.close(); }
错误原因复盘
你调用put(InputStream, destPath)时,传入的InputStream是尝试从HDFS的FileName.zip目录打开的,但HDFS的目录无法直接用fs.open()打开为流,因此抛出了"FileNotFoundException: Is a directory"——本质是误将目录当作普通文件处理。
内容的提问来源于stack exchange,提问作者Glarixon
相关产品推荐
相关产品推荐

