您的位置 首页 java

java io流RandomAccessFile类详解

RandomAccessFile简介

randomAccessFile 既可以读取文件内容,也可以向文件输出数据。同时,RandomAccessFile支持“随机访问”的方式,程序快可以直接跳转到文件的任意地方来读写数据。

由于RandomAccessFile可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。

OutputStream 、Writer等输出流不同的是,RandomAccessFile允许自由定义文件记录指针,RandomAccessFile可以不从开始的地方开始输出,因此RandomAccessFile可以向已存在的文件后追加内容。如果程序需要向已存在的文件后追加内容,则应该使用RandomAccessFile。

RandomAccessFile的方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其他 IO 节点。

RandomAccessFile的一个重要使用场景就是网络请求中的多线程下载及断点续传。

java io流RandomAccessFile类详解

本章学习路径

RandomAccessFile中的方法

  • RandomAccessFile的构造函数

RandomAccessFile类有两个构造函数,其实这两个 构造函数 基本相同,只不过是指定文件的形式不同——一个需要使用 String 参数来指定文件名,一个使用 File 参数来指定文件本身。除此之外,创建RandomAccessFile对象时还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,一共有4种模式。

“r” : ** 以只读的方式打开,调用结果对象的任何 write 方法都将导致抛出去 IOException。

“rw”: 打开以便读取和写入。

rws “: 打开以便读取和写入。相对于 “rw”,”rws” 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。

“rwd” : 打开以便读取和写入,相对于 “rw”,”rwd” 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。

  • RandomAccessFile的指针相关方法

RandomAccessFile既可以读文件,也可以写文件,所以类似于 InputStream 的read()方法,以及类似于OutputStream的write()方法,RandomAccessFile都具备。除此之外,RandomAccessFile具备两个特有的方法,来支持其随机访问的特性。

RandomAccessFile对象包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件指针记录位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会后移n个字节。除此之外,RandomAccessFile还可以自由移动该记录指针。下面就是RandomAccessFile具有的两个特殊方法,来操作记录指针,实现随机访问:

long getFilePointer( ):返回文件记录指针的当前位置

void seek(long pos ):将文件指针定位到pos的位置

skip byte s(int n)

该方法用于尝试跳过输入的n个字节以丢弃跳过的字节(跳过的字节不读取):int skipBytes(int n)

该方法可能跳过一些较少数量的字节(可能包括0),这可能由任意数量的条件引起,在跳过n个字节之前已经到大文件的末尾只是其中的一种可能

该方法不抛出EOFException,返回跳过的实际字节数,如果n为负数,则不跳过任何字节

FileDescriptor getFD() : 可以返回这个文件的文件描述符

native long length() : 可以返回文件的长度

native void setLength(long newLength) : 还可以设置文件的长度

close() : RandomAccessFile在对文件访问操作全部结束后,要调用 close ()方法来释放与其关联的所有系统资源

setLength 为什么还能设置文件长度?

你可以理解为这是一个”动态数组”!!假设你想要设置为newLength 长度

如果这个长度小于 实际长度(length方法返回的值), 文件被截断,并且如果getFilePointer 大于newLength ,那么它将变成newLength

如果 newLength大于 实际长度(length方法返回的值),则该文件将被扩展, 在此情况下,未定义文件扩展部分的内容。

seek 方法设置的偏移量,下一次的读写将从这个位置开始,偏移量的设置可能会超出文件末尾,这并不会改变什么,但是一旦你在这个超出文件末尾的偏移量位置写入数据,长度将会改变。

  • RandomAccessFile的读方法

int read()

从此文件中读取一个数据字节。

int read(byte[] b)

将最多 b.length 数组长度的数据字节从此文件读入 byte 数组。

int read(byte[] b, int off, int len)

将最多 len 个数据字节从此文件读入 byte 数组。

boolean readBoolean()

从此文件读取一个 boolean。

byte readByte()

从此文件读取一个有符号的八位值。

char read char ()

从此文件读取一个字符。

double readDouble()

从此文件读取一个 double。

float readFloat()

从此文件读取一个 Float

void readFully(byte[] b)

将 b.length 个字节从此文件读入 byte 数组,并从当前文件指针开始。

void readFully(byte[] b, int off, int len)

将正好 len 个字节从此文件读入 byte 数组,并从当前文件指针开始。

int readInt()

从此文件读取一个有符号的 32 位整数。

String readLine()

从此文件读取文本的下一行。

long readLong()

从此文件读取一个有符号的 64 位整数。

short readShort()

从此文件读取一个有符号的 16 位数。

int readUnsignedByte()

从此文件读取一个无符号的八位数。

int readUnsignedShort()

从此文件读取一个无符号的 16 位数。

String readUTF()

从此文件读取一个 字符串

  • RandomAccessFile的写方法

void write(byte[] b)

//将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。

void write(byte[] b, int off, int len)

//将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。

void write(int b)

//向此文件写入指定的字节。

void writeBoolean(boolean v)

//按单字节值将 boolean 写入该文件。

void writeByte(int v)

//按单字节值将 byte 写入该文件。

void writeBytes(String s)

//按字节序列将该字符串写入该文件。

void writeChar(int v)

//按双字节值将 char 写入该文件,先写高字节。

void writeChars(String s)

//按字符序列将一个字符串写入该文件。

void writeDouble(double v)

//使用 Double 类中的 doubleTo long Bits 方法将双精度参数转换为一个 long,然后按八字节数量将该 long 值写入该文件,先定高字节。

void writeFloat(float v)

//使用 Float 类中的 floatToIntBits 方法将浮点参数转换为一个 int,然后按四字节数量将该 long 值写入该文件,先定高字节。

例子1 利用 多线程 进行文件的写操作

public class RandomAccessFile Test {

public static void main(String[] args) throws Exception {

// 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件

RandomAccessFile raf = new RandomAccessFile(“D://abc.txt”, “rw”);

raf.setLength(1024*1024); // 预分配 1M 的文件空间

raf.close();

// 所要写入的文件内容

String s1 = “第一个字符串”;

String s2 = “第二个字符串”;

String s3 = “第三个字符串”;

String s4 = “第四个字符串”;

String s5 = “第五个字符串”;

// 利用多线程同时写入一个文件

new FileWriteThread(1024*1,s1.get Bytes ()).start(); // 从文件的1024字节之后开始写入数据

new FileWriteThread(1024*2,s2.getBytes()).start(); // 从文件的2048字节之后开始写入数据

new FileWriteThread(1024*3,s3.getBytes()).start(); // 从文件的3072字节之后开始写入数据

new FileWriteThread(1024*4,s4.getBytes()).start(); // 从文件的4096字节之后开始写入数据

new FileWriteThread(1024*5,s5.getBytes()).start(); // 从文件的5120字节之后开始写入数据

}

// 利用 线程 在文件的指定位置写入指定数据

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) {

e.printStackTrace();

} finally {

try {

raf.close();

} catch (Exception e) {

}

}

}

}

}

例子2 插入文件指定位置的指定内容

public class RandomAccessFileTest {

public static void main(String[] args)throws IOException {

String filePath=”E:Test.txt”;

FileTest.insert(filePath,1000,”插入指定位置指定内容”);

}

/**

* 插入文件指定位置的指定内容

* @param filePath 文件路径

* @param pos 插入文件的指定位置

* @param insertContent 插入文件中的内容

* @throws IOException

*/

public static void insert(String filePath,long pos,String insertContent)throws IOException{

RandomAccessFile raf=null;

File tmp=File.createTempFile(“tmp”,null);

tmp.deleteOnExit();

try {

// 以读写的方式打开一个RandomAccessFile对象

raf = new RandomAccessFile(new File(filePath), “rw”);

//创建一个临时文件来保存插入点后的数据

FileOutputStream fileOutputStream = new FileOutputStream(tmp);

FileInputStream fileInputStream = new FileInputStream(tmp);

//把文件记录指针定位到pos位置

raf.seek(pos);

raf.seek(pos);

//——下面代码将插入点后的内容读入临时文件中保存—–

byte[] bbuf = new byte[64];

//用于保存实际读取的字节数据

int hasRead = 0;

//使用循环读取插入点后的数据

while ((hasRead = raf.read(bbuf)) != -1) {

//将读取的内容写入临时文件

fileOutputStream.write(bbuf, 0, hasRead);

}

//—–下面代码用于插入内容 —–

//把文件记录指针重新定位到pos位置

raf.seek(pos);

//追加需要插入的内容

raf.write(insertContent.getBytes());

//追加临时文件中的内容

while ((hasRead = fileInputStream.read(bbuf)) != -1) {

//将读取的内容写入临时文件

raf.write(bbuf, 0, hasRead);

}

}catch (Exception e){

throw e;

}

}

}

例子3 实现从指定位置读取文件的功能

public class RandomAccessFileTest {

public static void main(String[] args)throws IOException {

String filePath=”E:Test.txt”;

RandomAccessFile raf=null;

File file=null;

try {

file=new File(filePath);

raf=new RandomAccessFile(file,”r”);

// 获取 RandomAccessFile对象文件指针的位置,初始位置为0

System.out.print(“输入内容:”+raf.getFilePointer());

//移动文件记录指针的位置

raf.seek(1000);

byte[] b=new byte[1024];

int hasRead=0;

//循环读取文件

while((hasRead=raf.read(b))>0){

//输出文件读取的内容

System.out.print(new String(b,0,hasRead));

}

}catch (IOException e){

e.printStackTrace();

}finally {

raf.close();

}

}

}

例子4 实现向文件中追加内容的功能

public class RandomAccessFileTest {

public static void main(String[] args)throws IOException {

String filePath=”E:Test.txt”;

RandomAccessFile raf=null;

File file=null;

try {

file=new File(filePath);

// 以读写的方式打开一个RandomAccessFile对象

raf=new RandomAccessFile(file,”rw”);

//将记录指针移动到该文件的最后

raf.seek(raf.length());

//向文件末尾追加内容

raf.writeChars(“这是追加内容。。”);

}catch (IOException e){

e.printStackTrace();

}finally {

raf.close();

}

}

例子5 综合读写定位插入文件内容

import java .io.FileNotFoundException;

import java.io.IOException;

import java.io.RandomAccessFile;

class Student {

private String name;

private int age;

public Student() {

super();

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Student(String name, int age) {

super();

this.name = name;

this.age = age;

}

}

public class RandomAccessFileTest {

public static void main(String[] args) {

RandomAccessFile randomAccessFile = null;

try { // 创建一个随机访问文件对象,并设置为可读写模式

randomAccessFile = new RandomAccessFile(“srcbeannewFile.txt”, “rw”);

System.out.println(“文件指针当前位置:” + randomAccessFile.getFilePointer());

// 使用writeChars方法把一串字符写到文件中

// randomAccessFile.writeChars(“I am here!”);

randomAccessFile.writeBytes(“I am here!”);

System.out.println(“使用readLine方法读取数据:”);

System.out.println(“此时文件指针当前位置:” + randomAccessFile.getFilePointer());

randomAccessFile.seek(0); // 重新把文件指针定位到开始处

String content = randomAccessFile.readLine();

while (content != null) {

System.out.println(content);

content = randomAccessFile.readLine(); // 使用read方法读取指定长度的字节

}

randomAccessFile.seek(0); // 重新把文件指针定位到开始处

byte[] b = new byte[10];

int length = randomAccessFile.read(b);

System.out.println(“真正读取的字节数:” + length);

String convertStr = new String(b);

System.out.println(“转换后的内容为:” + convertStr);

randomAccessFile.seek(0);

length = randomAccessFile.skipBytes(10);// 参数可以为负数,当为负数时,则该方法不起作用

System.out.println(“实际跳过的字节数:” + length);

content = randomAccessFile.readLine();

while (content != null) {

System.out.println(content);

content = randomAccessFile.readLine();

}

randomAccessFile.setLength(0);

Student[] studs = new Student[] { new Student(“andy”, 23), new Student(“lili”, 22) };

for (Student stud : studs) {

randomAccessFile.writeUTF(stud.getName());

randomAccessFile.writeInt(stud.getAge());

}

randomAccessFile.seek(0);

Student[] studCreated = new Student[2];

for (int i = 0; i < studCreated.length; i++) {

studCreated[i] = new Student();

studCreated[i].setName(randomAccessFile.readUTF());

studCreated[i].setAge(randomAccessFile.readInt());

System.out.println(“第” + i + “位学生的记录:”);

System.out.println(“name:” + studCreated[i].getName() + “ age:” + studCreated[i].getAge()); }

} catch (FileNotFoundException e) { e.printStackTrace();

} catch (IOException e) { e.printStackTrace();

} finally { try {

randomAccessFile.close();

} catch (IOException e) { e.printStackTrace();

}

}

}

}

文章来源:智云一二三科技

文章标题:java io流RandomAccessFile类详解

文章地址:https://www.zhihuclub.com/189500.shtml

关于作者: 智云科技

热门文章

网站地图