在实际项目中,输入数据往往是由许多小文件组成,这里的小文件是指小于HDFS系统Block大小的文件(默认128M), 然而每一个存储在HDFS中的文件、目录和块都映射为一个对象,存储在NameNode服务器内存中,通常占用150个字节。 如果有1千万个文件,就需要消耗大约3G的内存空间。如果是10亿个文件呢,简直不可想象。所以在项目开始前, 我们选择一种适合的方案来解决本项目的小文件问题
2、介绍
本地 D:\data目录下有 2012-09-17 至 2012-09-23 一共7天的数据集,我们需要将这7天的数据集按日期合并为7个大文件上传至 HDFS
3、数据
本地 D:\data目录下的所有数据,如下图所示
4、分析
基于项目的需求,我们通过下面几个步骤完成
1、获取 D:\data目录下的所有日期路径,循环所有日期路径,通过globStatus()方法获取所有txt格式文件路径。
2、最后通过IOUtils.copyBytes(in, out, 4096, false)方法将数据集合并为大文件,并上传至 HDFS
5、实现
自定义RegexAcceptPathFilter类实现 PathFilter,比如只接受D:\data\2012-09-17日期目录下txt格式的文件
/** * @ProjectName FileMerge * @PackageName com.buaa * @ClassName RegexAcceptPathFilter * @Description 接受 regex 格式的文件 * @Author 刘吉超 * @Date 2016-04-18 21:58:07 */ public static class RegexAcceptPathFilter implements PathFilter { private final String regex; public RegexAcceptPathFilter(String regex) { this.regex = regex; } @Override public boolean accept(Path path) { boolean flag = path.toString().matches(regex); return flag; } }
实现主程序 merge 方法,完成数据集的合并,并上传至 HDFS
/** * 合并 * * @param srcPath 源目录 * @param destPath 目标目录 */ public static void merge(String srcPath,String destPath) { try{ // 读取hadoop文件系统的配置 Configuration conf = new Configuration(); // 获取远端文件系统 URI uri = new URI(HDFSUri); FileSystem remote = FileSystem.get(uri, conf); // 获得本地文件系统 FileSystem local = FileSystem.getLocal(conf); // 获取data目录下的所有文件路径 Path[] dirs = FileUtil.stat2Paths(local.globStatus(new Path(srcPath))); FSDataOutputStream out = null; FSDataInputStream in = null; for (Path dir : dirs) { // 文件名称 String fileName = dir.getName().replace("-", ""); // 只接受目录下的.txt文件 FileStatus[] localStatus = local.globStatus(new Path(dir + "/*"), new RegexAcceptPathFilter("^.*.txt$")); // 获得目录下的所有文件 Path[] listedPaths = FileUtil.stat2Paths(localStatus); // 输出路径 Path block = new Path(destPath + "/" + fileName + ".txt"); // 打开输出流 out = remote.create(block); for (Path p : listedPaths) { // 打开输入流 in = local.open(p); // 复制数据 IOUtils.copyBytes(in, out, 4096, false); // 关闭输入流 in.close(); } if (out != null) { // 关闭输出流 out.close(); } } }catch(Exception e){ logger.error("", e); } }
6、一些运行代码
/** * main方法 * * @param args */ public static void main(String[] args) { merge("D:\\data\\*","/buaa/tv"); }
7、结果
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【刘超★ljc】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
代码及数据:下载