Java RandomAccessFile的用法詳解
RandomAccessFile
RandomAccessFile是用來訪問那些保存數(shù)據(jù)記錄的文件的,你就可以用seek( )方法來訪問記錄,并進行讀寫了。這些記錄的大小不必相同;但是其大小和位置必須是可知的。但是該類僅限于操作文件。
RandomAccessFile不屬于InputStream和OutputStream類系的。實際上,除了實現(xiàn)DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也實現(xiàn)了這兩個接口),它和這兩個類系毫不相干,甚至不使用InputStream和OutputStream類中已經(jīng)存在的任何功能;它是一個完全獨立的類,所有方法(絕大多數(shù)都只屬于它自己)都是從零開始寫的。這可能是因為RandomAccessFile能在文件里面前后移動,所以它的行為與其它的I/O類有些根本性的不同??偠灾?,它是一個直接繼承Object的,獨立的類。
基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream結(jié)合起來,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移動用的seek( ),以及判斷文件大小的length( )、skipBytes()跳過多少字節(jié)數(shù)。此外,它的構(gòu)造函數(shù)還要一個表示以只讀方式("r"),還是以讀寫方式("rw")打開文件的參數(shù) (和C的fopen( )一模一樣)。它不支持只寫文件。
只有RandomAccessFile才有seek搜尋方法,而這個方法也只適用于文件。BufferedInputStream有一個mark( )方法,你可以用它來設(shè)定標記(把結(jié)果保存在一個內(nèi)部變量里),然后再調(diào)用reset( )返回這個位置,但是它的功能太弱了,而且也不怎么實用。
RandomAccessFile的絕大多數(shù)功能,但不是全部,已經(jīng)被JDK 1.4的nio的"內(nèi)存映射文件(memory-mapped files)"給取代了,你該考慮一下是不是用"內(nèi)存映射文件"來代替RandomAccessFile了。
import java.io.IOException;
import java.io.RandomAccessFile;
public class TestRandomAccessFile {
public static void main(String[] args) throws IOException {
RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");
for (int i = 0; i < 10; i++) {
//寫入基本類型double數(shù)據(jù)
rf.writeDouble(i * 1.414);
}
rf.close();
rf = new RandomAccessFile("rtest.dat", "rw");
//直接將文件指針移到第5個double數(shù)據(jù)后面
rf.seek(5 * 8);
//覆蓋第6個double數(shù)據(jù)
rf.writeDouble(47.0001);
rf.close();
rf = new RandomAccessFile("rtest.dat", "r");
for (int i = 0; i < 10; i++) {
System.out.println("Value " + i + ": " + rf.readDouble());
}
rf.close();
}
}
內(nèi)存映射文件
內(nèi)存映射文件能讓你創(chuàng)建和修改那些因為太大而無法放入內(nèi)存的文件。有了內(nèi)存映射文件,你就可以認為文件已經(jīng)全部讀進了內(nèi)存,然后把它當(dāng)成一個非常大的數(shù)組來訪問。這種解決辦法能大大簡化修改文件的代碼。
fileChannel.map(FileChannel.MapMode mode, long position, long size)將此通道的文件區(qū)域直接映射到內(nèi)存中。注意,你必須指明,它是從文件的哪個位置開始映射的,映射的范圍又有多大;也就是說,它還可以映射一個大文件的某個小片斷。
MappedByteBuffer是ByteBuffer的子類,因此它具備了 ByteBuffer的所有方法,但新添了force()將緩沖區(qū)的內(nèi)容強制刷新到存儲設(shè)備中去、load()將存儲設(shè)備中的數(shù)據(jù)加載到內(nèi)存中、 isLoaded()位置內(nèi)存中的數(shù)據(jù)是否與存儲設(shè)置上同步。這里只簡單地演示了一下put()和get()方法,除此之外,你還可以使用 asCharBuffer( )之類的方法得到相應(yīng)基本類型數(shù)據(jù)的緩沖視圖后,可以方便的讀寫基本類型數(shù)據(jù)。
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class LargeMappedFiles {
static int length = 0x8000000; // 128 Mb
public static void main(String[] args) throws Exception {
// 為了以可讀可寫的方式打開文件,這里使用RandomAccessFile來創(chuàng)建文件。
FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel();
//注意,文件通道的可讀可寫要建立在文件流本身可讀寫的基礎(chǔ)之上
MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
//寫128M的內(nèi)容
for (int i = 0; i < length; i++) {
out.put((byte) 'x');
}
System.out.println("Finished writing");
//讀取文件中間6個字節(jié)內(nèi)容
for (int i = length / 2; i < length / 2 + 6; i++) {
System.out.print((char) out.get(i));
}
fc.close();
}
}
盡管映射寫似乎要用到FileOutputStream,但是映射文件中的所有輸出 必須使用RandomAccessFile,但如果只需要讀時可以使用FileInputStream,寫映射文件時一定要使用隨機訪問文件,可能寫時要讀的原因吧。
該程序創(chuàng)建了一個128Mb的文件,如果一次性讀到內(nèi)存可能導(dǎo)致內(nèi)存溢出,但這里訪問好像只是一瞬間的事,這是因為,真正調(diào)入內(nèi)存的只是其中的一小部分,其余部分則被放在交換文件上。這樣你就可以很方便地修改超大型的文件了(最大可以到2 GB)。注意,Java是調(diào)用操作系統(tǒng)的"文件映射機制"來提升性能的。
RandomAccessFile類的應(yīng)用:
/*
* 程序功能:演示了RandomAccessFile類的操作,同時實現(xiàn)了一個文件復(fù)制操作。
*/
package com.lwj.demo;
import java.io.*;
public class RandomAccessFileDemo {
public static void main(String[] args) throws Exception {
RandomAccessFile file = new RandomAccessFile("file", "rw");
// 以下向file文件中寫數(shù)據(jù)
file.writeInt(20);// 占4個字節(jié)
file.writeDouble(8.236598);// 占8個字節(jié)
file.writeUTF("這是一個UTF字符串");// 這個長度寫在當(dāng)前文件指針的前兩個字節(jié)處,可用readShort()讀取
file.writeBoolean(true);// 占1個字節(jié)
file.writeShort(395);// 占2個字節(jié)
file.writeLong(2325451l);// 占8個字節(jié)
file.writeUTF("又是一個UTF字符串");
file.writeFloat(35.5f);// 占4個字節(jié)
file.writeChar('a');// 占2個字節(jié)
file.seek(0);// 把文件指針位置設(shè)置到文件起始處
// 以下從file文件中讀數(shù)據(jù),要注意文件指針的位置
System.out.println("——————從file文件指定位置讀數(shù)據(jù)——————");
System.out.println(file.readInt());
System.out.println(file.readDouble());
System.out.println(file.readUTF());
file.skipBytes(3);// 將文件指針跳過3個字節(jié),本例中即跳過了一個boolean值和short值。
System.out.println(file.readLong());
file.skipBytes(file.readShort()); // 跳過文件中“又是一個UTF字符串”所占字節(jié),注意readShort()方法會移動文件指針,所以不用加2。
System.out.println(file.readFloat());
//以下演示文件復(fù)制操作
System.out.println("——————文件復(fù)制(從file到fileCopy)——————");
file.seek(0);
RandomAccessFile fileCopy=new RandomAccessFile("fileCopy","rw");
int len=(int)file.length();//取得文件長度(字節(jié)數(shù))
byte[] b=new byte[len];
file.readFully(b);
fileCopy.write(b);
System.out.println("復(fù)制完成!");
}
}
RandomAccessFile 插入寫示例:
/**
*
* @param skip 跳過多少過字節(jié)進行插入數(shù)據(jù)
* @param str 要插入的字符串
* @param fileName 文件路徑
*/
public static void beiju(long skip, String str, String fileName){
try {
RandomAccessFile raf = new RandomAccessFile(fileName,"rw");
if(skip < 0 || skip > raf.length()){
System.out.println("跳過字節(jié)數(shù)無效");
return;
}
byte[] b = str.getBytes();
raf.setLength(raf.length() + b.length);
for(long i = raf.length() - 1; i > b.length + skip - 1; i--){
raf.seek(i - b.length);
byte temp = raf.readByte();
raf.seek(i);
raf.writeByte(temp);
}
raf.seek(skip);
raf.write(b);
raf.close();
} catch (Exception e) {
e.printStackTrace();
}
}
利用RandomAccessFile實現(xiàn)文件的多線程下載,即多線程下載一個文件時,將文件分成幾塊,每塊用不同的線程進行下載。下面是一個利用多線程在寫文件時的例子,其中預(yù)先分配文件所需要的空間,然后在所分配的空間中進行分塊,然后寫入:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* 測試利用多線程進行文件的寫操作
*/
public class Test {
public static void main(String[] args) throws Exception {
// 預(yù)分配文件所占的磁盤空間,磁盤中會創(chuàng)建一個指定大小的文件
RandomAccessFile raf = new RandomAccessFile("D://abc.txt", "rw");
raf.setLength(1024*1024); // 預(yù)分配 1M 的文件空間
raf.close();
// 所要寫入的文件內(nèi)容
String s1 = "第一個字符串";
String s2 = "第二個字符串";
String s3 = "第三個字符串";
String s4 = "第四個字符串";
String s5 = "第五個字符串";
// 利用多線程同時寫入一個文件
new FileWriteThread(1024*1,s1.getBytes()).start(); // 從文件的1024字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*2,s2.getBytes()).start(); // 從文件的2048字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*3,s3.getBytes()).start(); // 從文件的3072字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*4,s4.getBytes()).start(); // 從文件的4096字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*5,s5.getBytes()).start(); // 從文件的5120字節(jié)之后開始寫入數(shù)據(jù)
}
// 利用線程在文件的指定位置寫入指定數(shù)據(jù)
static class FileWriteThread extends Thread{
private int skip;
private byte[] content;
public FileWriteThread(int skip,byte[] content){
this.skip = skip;
this.content = content;
}
public void run(){
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile("D://abc.txt", "rw");
raf.seek(skip);
raf.write(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
raf.close();
} catch (Exception e) {
}
}
}
}
}
以上這篇Java RandomAccessFile的用法詳解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
- java使用randomaccessfile在文件任意位置寫入數(shù)據(jù)
- Java RandomAccessFile 指定位置實現(xiàn)文件讀取與寫入
- Java使用RandomAccessFile類對文件進行讀寫
- Java I/O深入學(xué)習(xí)之File和RandomAccessFile
- Java中IO流 RandomAccessFile類實例詳解
- java使用RandomAccessFile類基于指針讀寫文件實例代碼
- Java核心編程之文件隨機讀寫類RandomAccessFile詳解
- RandomAccessFile簡介_動力節(jié)點Java學(xué)院整理
- java文件操作工具類分享(file文件工具類)
- Java最全文件操作實例匯總
- Java RandomAccessFile基本文件操作示例
相關(guān)文章
詳解Java實現(xiàn)多種方式的http數(shù)據(jù)抓取
本篇文章主要介紹了Java實現(xiàn)多種方式的http數(shù)據(jù)抓取,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧。2016-12-12
Java Testcontainers庫實現(xiàn)測試功能
這篇文章主要介紹了Java Testcontainers庫實現(xiàn)測試功能,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09
SpringBoot集成ElasticSearch的示例代碼
Elasticsearch是用Java語言開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,是一種流行的企業(yè)級搜索引擎,本文給大家介紹SpringBoot集成ElasticSearch的示例代碼,感興趣的朋友一起看看吧2022-02-02
Java讀取一行空格隔開的數(shù)字字符串并求出這些數(shù)字的和方法
今天小編就為大家分享一篇Java讀取一行空格隔開的數(shù)字字符串并求出這些數(shù)字的和方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07
Mybatis-Plus雪花id的使用以及解析機器ID和數(shù)據(jù)標識ID實現(xiàn)
這篇文章主要介紹了Mybatis-Plus雪花id的使用以及解析機器ID和數(shù)據(jù)標識ID實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

