對於一般檔案,都有滿足隨機讀寫的api。而hadoop中的讀api很簡單用FSDataInputStream類就可以滿足一般要求,而hadoop中的寫操作卻是和普通java操作不一樣。
hadoop對於寫操作提供了一個類:FSDataOutputStream,這個類重載了很多write方法,用於寫入很多類型的資料:比如位元組數組,long,int,char等等。像FSDataInputStream一樣,要獲得FSDataOutputStream的執行個體,必須通過FileSystem該類來和HDFS建立串連,然後通過路徑返回FSDataOutputStream執行個體。FileSystem返回FSDataOutputStream執行個體的方法有兩組:
- create(Path p)函數,建立一個空檔案,然後可以向該檔案順序寫入
- append(Path p)函數,開啟一個已有檔案,並最做檔案末尾追加資料
以上兩組函數都有多個重載版本,可以查閱手冊。FSDataOutputStream不允許在檔案中定位(而FSDataInputStream可以),這是因為hadoop只允許在一個已開啟檔案順序寫入或在檔案尾追加資料,不允許在結尾之外其他檔案寫入資料。
在使用append的操作時可能返回異常dfs.support.append未設定為true,只要才hdfs-site.xml中把該屬性設定為true
<property> <name>dfs.support.append</name> <value>false</value> <description>Does HDFS allow appends to files? This is currently set to false because there are bugs in the "append code" and is not supported in any prodction cluster. </description></property>
而且0.20的早起版本也不支援append操作,官方文檔的建議是如果追加資料就重新create一個檔案。使用的時候應該謹慎一點。
當讀取檔案時若要返迴文件的大小,用下列代碼:
FileStatus status=hdfs.getFileStatus(p);return status.getLen();
但是當對檔案寫入時,FileStatus的getLen函數返回的不是當前的大小,因為FSDataInputStream在寫入資料時,資料會緩衝,只有當寫入的資料滿64M(塊大小)時或者關閉檔案時,才會把資料寫入到檔案中去。連續寫入資料時,為了即時擷取當前檔案大小,如果連續關閉開啟檔案勢必會影響效率。可以這樣解決:
long result;if(outFsData!=null){//FSDataInputStream對象執行個體result=writeInitSize+outFsData.size()//檔案開啟時的長度}else{FileStatus status=hdfs.getFileStatus(p);result=status.getLen();//這個getLen()返回的是int型,最大也就是4G,要注意}return result;
FSDataInputStream該類的size函數就是返回的緩衝區寫入的資料的大小。