java 文件随机读取_Java 实现文件随机读写-RandomAccessFile
現有如下的一個需求,向已存在1G數據的txt文本里末尾追加一行文字,內容如下“Lucene是一款非常優秀的全文檢索庫”。可能大多數朋友會覺得這個需求很easy,說實話,確實easy,然后XXX君開始實現了,直接使用Java中的流讀取了txt文本里原來所有的數據轉成字符串后,然后拼接了“Lucene是一款非常優秀的全文檢索庫”,又寫回文本里了,至此,大功告成。后來需求改了,向5G數據的txt文本里追加了,結果XXX君傻了,他內存只有4G,如果強制讀取所有的數據并追加,會報內存溢出的異常。
其實上面的需求很簡單,如果我們使用JAVA IO體系中的RandomAccessFile類來完成的話,可以實現零內存追加。其實這就是支持任意位置讀寫類的強大之處。
在這之前,還是先啰嗦的介紹下RandomAccessFile這個類,RandomAccessFile是Java中輸入,輸出流體系中功能最豐富的文件內容訪問類,它提供很多方法來操作文件,包括讀寫支持,與普通的IO流相比,它最大的特別之處就是支持任意訪問的方式,程序可以直接跳到任意地方來讀寫數據。
如果我們只希望訪問文件的部分內容,而不是把文件從頭讀到尾,使用RandomAccessFile將會帶來更簡潔的代碼以及更好的性能。
下面來看下RandomAccessFile類中比較重要的2個方法,其他的和普通IO類似,在這里,就不詳細說明了。
方法名
作用
getFilePointer()
返回文件記錄指針的當前位置
seek(long pos)
將文件記錄指針定位到pos的位置
下面散仙給出示例,分析下怎么使用RandomAccessFile
首先,我們先看下要操作的文本文件的內容截圖。
功能one,讀取任意位置的數據,代碼如下
Java代碼 ?
/**
*?讀的方法
*?@param?path?文件路徑
*?@param?pointe?指針位置
*?**/
public?static?void?randomRed(String?path,int?pointe){
try{
//RandomAccessFile?raf=new?RandomAccessFile(new?File("D:\\3\\test.txt"),?"r");
/**
*?model各個參數詳解
*?r?代表以只讀方式打開指定文件
*?rw?以讀寫方式打開指定文件
*?rws?讀寫方式打開,并對內容或元數據都同步寫入底層存儲設備
*?rwd?讀寫方式打開,對文件內容的更新同步更新至底層存儲設備
*
*?**/
RandomAccessFile?raf=new?RandomAccessFile(path,?"r");
//獲取RandomAccessFile對象文件指針的位置,初始位置是0
System.out.println("RandomAccessFile文件指針的初始位置:"+raf.getFilePointer());
raf.seek(pointe);//移動文件指針位置
byte[]??buff=new?byte[1024];
//用于保存實際讀取的字節數
int?hasRead=0;
//循環讀取
while((hasRead=raf.read(buff))>0){
//打印讀取的內容,并將字節轉為字符串輸入
System.out.println(new?String(buff,0,hasRead));
}
}catch(Exception?e){
e.printStackTrace();
}
}
測試代碼
Java代碼 ?
public?static?void?main(String[]?args)?{
String?path="D:\\3\\test.txt";
int?seekPointer=20;
randomRed(path,seekPointer);//讀取的方法
//randomWrite(path);//追加寫的方法
//insert(path,?33,?"\nlucene是一個優秀的全文檢索庫");
}
運行效果:
Java代碼 ?
RandomAccessFile文件指針的初始位置:0
is?a?teacher
hadoop?is?perfect
功能two,追加數據,代碼如下
Java代碼 ?
/**
*?追加方式
*?寫的方法
*?@param?path?文件路徑
*?***/
public?static?void?randomWrite(String?path){
try{
/**以讀寫的方式建立一個RandomAccessFile對象**/
RandomAccessFile?raf=new?RandomAccessFile(path,?"rw");
//將記錄指針移動到文件最后
raf.seek(raf.length());
raf.write("我是追加的?\r\n".getBytes());
}catch(Exception?e){
e.printStackTrace();
}
}
測試代碼
Java代碼 ?
public?static?void?main(String[]?args)?{
String?path="D:\\3\\test.txt";
//int?seekPointer=20;
//?randomRed(path,seekPointer);//讀取的方法
randomWrite(path);//追加寫的方法
//insert(path,?33,?"\nlucene是一個優秀的全文檢索庫");
}
運行效果:
功能three,任意位置插入數據,代碼如下
Java代碼 ?
/**
*?實現向指定位置
*?插入數據
*?@param?fileName?文件名
*?@param?points?指針位置
*?@param?insertContent?插入內容
*?**/
public?static?void?insert(String?fileName,long?points,String?insertContent){
try{
File?tmp=File.createTempFile("tmp",?null);
tmp.deleteOnExit();//在JVM退出時刪除
RandomAccessFile?raf=new?RandomAccessFile(fileName,?"rw");
//創建一個臨時文件夾來保存插入點后的數據
FileOutputStream?tmpOut=new?FileOutputStream(tmp);
FileInputStream?tmpIn=new?FileInputStream(tmp);
raf.seek(points);
/**將插入點后的內容讀入臨時文件夾**/
byte?[]?buff=new?byte[1024];
//用于保存臨時讀取的字節數
int?hasRead=0;
//循環讀取插入點后的內容
while((hasRead=raf.read(buff))>0){
//?將讀取的數據寫入臨時文件中
tmpOut.write(buff,?0,?hasRead);
}
//插入需要指定添加的數據
raf.seek(points);//返回原來的插入處
//追加需要追加的內容
raf.write(insertContent.getBytes());
//最后追加臨時文件中的內容
while((hasRead=tmpIn.read(buff))>0){
raf.write(buff,0,hasRead);
}
}catch(Exception?e){
e.printStackTrace();
}
}
測試代碼
Java代碼 ?
public?static?void?main(String[]?args)?{
String?path="D:\\3\\test.txt";
//int?seekPointer=20;
//?randomRed(path,seekPointer);//讀取的方法
//?randomWrite(path);//追加寫的方法
insert(path,?33,?"\nlucene是一個優秀的全文檢索庫");
}
運行效果:
至此,RandomAccessFile類的幾個功能,散仙在代碼中已給出實現了,現在回到本文開始前的提的那個需求,用RandomAccessFile類就可以輕而易舉的完成了,另外需要注意的是,向指定位置插入數據,是散仙自己改造的功能,RandomAccessFile并不直接支持,需要新建一個緩沖區臨時空間,存數據,然后在寫,因為一旦數據量上了級別,在任意位置插入數據,是很耗內存的,這個也就是為什么hadoop的HDFS文件系統,只支持append的方式,而沒有提供修改的操作。
另外我們可以用RandomAccessFile這個類,來實現一個多線程斷點下載的功能,用過下載工具的朋友們都知道,下載前都會建立兩個臨時文件,一個是與被下載文件大小相同的空文件,另一個是記錄文件指針的位置文件,每次暫停的時候,都會保存上一次的指針,然后斷點下載的時候,會繼續從上一次的地方下載,從而實現斷點下載或上傳的功能,有興趣的朋友們可以自己實現下。
總結
以上是生活随笔為你收集整理的java 文件随机读取_Java 实现文件随机读写-RandomAccessFile的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 接口 返回值_java api
- 下一篇: java excel data 导入数据