在实现《Hadoop高级编程》一书中第9章的一个例子:将HBase用于图片管理系统
中,遇到了一个很让人头疼的问题:FileNotFoundException
。虽然异常很简单,可是文件确实存在那了。因而开始了长时间的排错之旅。java
该例子是将一堆小图片文件合成一个大文件,并将各个小文件的位置索引存入HBase中。有一个DatedPhoto
类,用于存放时间(long
)以及图片(byte[]
);还有一个PhotoLocation
类,用于存放位置(long
)、时间(long
)和文件名(String
)。位置是小文件在大文件中的字节位置,文件名是合成的大文件名,按序号命名。PhotoLocation
类还提供了toBytes
和fromBytes
函数,用于将三种信息字节化后写入HBase以及从HBase中读出索引信息后还原成位置, 时间 和 文件名 信息。其他为写入类,读出类。总体很是简单。编程
写的时候彻底没有问题,文件成功生成,HBase中保存了索引。可是读取的时候,出现问题:一直报FileNotFoundException
异常,而路径并未出错并且文件存在。数组
这究竟是怎么一回事呢?由于用的是SequenceFile
中的内部类Reader
和Writer
,而Hadoop 2.2.0
的API中并无找到这两个东西,便从源码入手看看是否是这个类的问题。按照执行流程过了一遍,任何问题都没发现。因为错误定位在SequenceFile.Reader
的构造函数中getFileStatus
上,便从新写了一个类测试FileSystem
类的getFileStatus
类,发现彻底没有问题,不是这出的错误。函数
PhotoDataReader
类是辅助读出数据的类,被PhotoReader
类调用。错误就定位在了该类的构造上。查看PhotoDataReader
类构造函数,其功能就是接受参数,调用SequenceFile.Reader
的构造函数。输出PhotoDataReader
接收到的参数:file
(String
)、user
(UUID
)、conf
(Configuration
),三者都没问题,可是出现了一个很奇怪的现象:oop
执行测试
System.out.println("file:"+ _file + "sadasdsasdssssss");
时,后面的那一串字符串竟然不显示!code
看来问题就出如今_file
参数上面。可是无论怎么输出_file
的值,的确就是我要的那个文件名的字符串。彷佛这是个根本就不该该出现的问题。而后输出_file
的字符串长度,明明只有1个字符的文件名,显示的长度为112!看来问题就在这!索引
问题究竟出如今哪呢?继续向上找,发现参数是PhotoReader
传给它的;PhotoReader
又经过读取HBase中的索引记录获得后用PhotoLocation
的fromBytes
函数获得…… fromBytes
函数?其实现的是将一个包含索引位置 、时间 与 文件名的128位字符数组分开而后生成三个值。索引位置与时间均为long
型,字符数组均为8位,没有问题。可是文件名为字符串,合成字符数组时用的length
函数,可是还原时就把除索引位置与时间的16位排除后剩下的112位所有用来生成字符串了!生成字符串用Bytes.bytes()
和 new String
均没法生成原长度的字符串。图片
既然知道了缘由,解决也好办了。要么设个长度位,要么用定长字符串,要么干脆在HBase分开存储。看来,有时候报错,问题每每出如今细节上,仔细思考每一处细节,能够减小不少的排错时间。至少此次我花了很多时间。字符串