假设客户端应用程序使用FileSplit
对象从相应文件中读取实际字节。
为此,必须通过以下代码从InputStream
创建FileSplit
对象:
FileSplit split = ... // The FileSplit reference
FileSystem fs = ... // The HDFS reference
FSDataInputStream fsin = fs.open(split.getPath());
long start = split.getStart()-1; // Byte before the first
if (start >= 0)
{
fsin.seek(start);
}
在某些情况下,例如Hadoop
MapReduce
LineRecordReader
类,会将流调整为-1。但是,FSDataInputStream
seek()
方法的文档明确说明,在寻找某个位置后,下一次读取将来自该位置,这意味着(?)上面的代码将关闭1个字节( ?)。
所以,问题是,那" -1"所有InputSplit阅读案例都需要调整吗?
顺便说一句,如果一个人想要正确读取FileSplit
,那么寻找它的开始是不够的,因为每个分割也有一个可能与实际HDFS文件末尾不同的结尾。因此,相应的InputStream
应该是"有界",即具有最大长度,如下所示:
InputStream is = new BoundedInputStream(fsin, split.getLength());
在这种情况下," native"上面创建了fsin
个Steam,使用了org.apache.commons.io.input.BoundedInputStream
类来实现" bounding"。
更新
显然,只有对LineRecordReader
类的一个用例行进行调整时才需要进行调整,这超出了分割的范围,以确保它读取完整的最后一行。
有关详细信息的详细讨论可以在earlier question和MAPREDUCE-772的评论中找到。
答案 0 :(得分:2)
寻找位置0意味着下一次调用InputStream.read()将读取字节0.寻找位置-1很可能会抛出异常。
当您在谈论示例和源代码中的标准模式时,您指的是什么?
当你注意到时,拆分不是必然的 - 例如采用TextInputFormat和可以拆分的文件。处理拆分的记录阅读器将:
重复此过程,直到找到的下一个换行符超过分割结束,或者找到EOF。因此,您可以看到,在这种情况下,拆分的实际边界可能会从输入拆分
指定的位置右移<强>更新强>
从LineRecordReader引用此代码块:
if (codec != null) {
in = new LineReader(codec.createInputStream(fileIn), job);
end = Long.MAX_VALUE;
} else {
if (start != 0) {
skipFirstLine = true;
--start;
fileIn.seek(start);
}
in = new LineReader(fileIn, job);
}
if (skipFirstLine) { // skip first line and re-establish "start".
start += in.readLine(new Text(), 0,
(int)Math.min((long)Integer.MAX_VALUE, end - start));
}
--start
语句最有可能用于避免在换行符上开始拆分并返回空行作为第一条记录。您可以看到,如果发生搜索,则跳过第一行以确保文件拆分不返回重叠记录