最近仔细研究了以下公司中使用的SequenceFile文件格式,SequenceFile的格式比较紧凑,实现了从中间读取文件内容(便于hadoop将文件进行适当地切分),同时也可以支持仅读取文件的元数据功能。
概述
经过总结后的文件格式图大概如下:
其中进入到SequenceFile的所有记录,都需要根据一定的hash规则确定一个HashKey。相对而言,记录块是比较简单的,每个记录块中仅包含块的大小,以及该块的数据;元数据就相对而言比较复杂,其中Metadata size是总体的记录数,每个HashKey均可以直接定位到记录的位置(offset, length, number记载着这些信息)。
其中需要注意的是,记录是严格有序的,写文件需要按照HashKey的顺序进行写入,也就是说,不能向该文件中append一条HashKey在当前Key之前的数据,一旦文件写完成,可能不能再更改。
实现的类图大概如下:
其中Writer负责写入文件,最重要的方法就是append,注意append的key顺序要保证;Reader负责读取文件,遍历next直到没有可用数据。
文件的写入
写入是由多次append执行的,每次append仅仅会写入其中的RecordBlock数据,而将元数据放在内存中:
if (length < 0) { throw new IOException("negative length values not allowed: " + length); } this.out.write(val, offset, length); ++this.number;
等到最后所有数据都已经写入完成后,执行writeTailer写入尾部的文件特征码,版本,元数据和元数据长度等信息:
private void writeTailer() throws IOException { this.lastPos = this.out.getPos(); this.out.write(XXSequenceFile.VERSION, 0, XXSequenceFile.VERSION.length); Text.writeString(this.out, valClass.getName()); this.metadata.write(this.out); long currentPos = this.out.getPos(); this.out.writeInt((int) (currentPos - this.lastPos)); }
经过测试,我们向其中写入3条String数据:{“A”, “BA”, “Cba”}(其hash值分别为1,63,2)的结果为:
0000000: 0141 0343 6261 0242 414d 5a53 4551 0119 .A.Cba.BAXXSEQ.. 0000010: 6f72 672e 6170 6163 6865 2e68 6164 6f6f org.apache.hadoo 0000020: 702e 696f 2e54 6578 7400 0000 0003 0000 p.io.Text....... 0000030: 0001 3100 0000 0000 0000 0000 0000 0000 ..1............. 0000040: 0000 0200 0000 0000 0000 0100 0000 0132 ...............2 0000050: 0000 0000 0000 0002 0000 0000 0000 0004 ................ 0000060: 0000 0000 0000 0001 0000 0002 3633 0000 ............63.. 0000070: 0000 0000 0006 0000 0000 0000 0003 0000 ................ 0000080: 0000 0000 0001 0000 007d 0a .........}.
文件的读取
那么这种类型的文件,读取从哪里开始?就是从最后面的length(int格式),我们直接跳转到最后4个字节:
this.in.seek(this.length - 4); int tailLength = this.in.readInt(); this.contentEnd = this.length - 4 - tailLength; this.in.seek(this.contentEnd);
这样可以直接定位到元数据的位置,然后将读取元数据至内存:
this.metadata.readFields(this.in);
最后通过setMeta()方法,设置key要读取的位置,其中参数就为HashKey,根据HashKey已经能够查找到对应的offset偏移量,定位到记录的所在:
XXSequenceFileMeta smeta = this.metadata.get(meta); if (smeta != null) { this.partIn = new XXSequenceFile.PartInputStream(this.in, smeta.getOffset(), smeta.getOffset() + smeta.getLength()); this.number = smeta.getNumber(); } else { this.partIn = new MzSequenceFile.PartInputStream(this.in); this.number = 0; }
这样就实现了一整套SequenceFile文件写入/读取的功能,文件格式紧凑,并且可以从任意地方开始读取。
相关推荐
业务需要hive读取SequenceFile文件,所以把TextFile类型转SequenceFile,再导入hive
Hadoop中将SequenceFile转换成MapFile的主要方法:给Sequencefile重建索引的程序
小文件合并Sequencefile word.jar
sequencefile&mapfile相关测试代码
SequenceFile文件格式
中文文档转成sequencefile文件格式,便于在hadoop下使用操作,java代码
利用Hadoop的sequencefile处理小文件的小程序
排序-CBIR-on-hadoop 将图像转换为 Hadoop SequenceFile 格式,适用于基于内容的图像检索系统。
2)使用SequenceFile对以上文件进行封装,生成一个独立文件,压缩格式任意; 3)实现以下的三种方式的查询: 3.1)给出文件名,可以从序列文件整体读取文件并存储到指定的位置; 3.2)给出某个整数的key,可以读取...
spark-SequenceFile及MapFile讲解
1.1 SequenceFile概述 1.2 SequenceFile压缩 1.4 SequenceFile读取文件 1.5 SequenceFile总结
版权声明:本文为CSDN博主「一瓢一瓢的饮 alanchan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/chenwewi520feng/article/details/13
一般情况下有四种处理海量小文件的方法,分别为默认输入格式TextInputFormat、为处理小文件而设计的CombineFileInputFormat输入格式、SequenceFile技术以及Harballing技术。为了比较在相同的Hadoop分布式环境下这四...
序列文件示例 使用序列文件的示例集合 设置: 克隆项目 cd /tmp && git clone https://github.com/sakserv/sequencefile-examples.git ... hadoop jar target/sequencefile-examples-0.0.1-SNAPSHOT.jar
SequenceFile学习的Java Demo代码 里面包括合并小文件,读取SequenceFile文件,写SequenceFile文件
读从hadoop文件系统导出的sequencefile格式的文件 一行一行读 存储成数组
升级glib解决Hadoop WARN util.NativeCodeLoader: ... 和 SequenceFile doesn't work with GzipCodec without native-hadoop code 问题, 具体请参见博文:https://blog.csdn.net/l1028386804/article/details/88420473
Apache Hive 的 InputFormat,在查询 SequenceFiles 时将返回 (Text) 键和 (Text) 值。 我需要在不拆分内容的情况下完整解析大量文本文件。 HDFS 在处理大型连续... 如果您的 SequenceFile 在其键或值中包含 Ctrl+A
关于输入,将普通视频格式转换为key为Text,值为video的二进制数据的SequenceFile格式关于输出,输出也是SequenceFle,key是Text image id,value是image的二进制数据。 这些图像 SequenceFile 可用于以下 ...
关于mrmlf 该库提供了一个扩展输入格式,即MultilineInputFormat... 现实世界中的一种重要数据格式是多行形式,其中一个集成记录被拆分为多个自然行(由\r或\n分隔)。 例如,说明程序中的音乐CD元数据: <CD> <TIT