在實現《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分開存儲。看來,有時候報錯,問題每每出如今細節上,仔細思考每一處細節,能夠減小不少的排錯時間。至少此次我花了很多時間。字符串