Java IO ——RandomAccessFile

Java IO ——RandomAccessFile

RandomAccessFile简介

RandomAccessFile 既可以读取文件也可以写入文件。
RandomAccessFile 最大的优势就是随机访问,能够直接跳转到任意位置进行文件的读写操作。
适用场景
如果需要访问文件的部分内容,而不是把文件从头读到尾,RandomAccessFile是最好的选择,因此RandomAccessFile经常用在网络请求中的多线程下载以及断点续传。

RandomAccessFile的使用

RandomAccessFile的创建方式有以下两种:

RandomAccessFile(File file,String mode);

RandomAccessFile(String fileName,String mode);

第一个参数是需要访问的文件
第二个参数是访问文件时的模式,主要为下面两个

  • “r" 以只读的方式打开
  • "rw"以读取和写入的方式打开

RandomAccessFile提供的方法

  1. read()方法

RandomAccessFile提供了一个可以从文件中读取字节的方法:

int read()

该方法会从RandomAccessFile当前指针位置读取一个byte(8位) 填充到int的低八位, 高24位为0, 返回值范围正数: 0~255, 如果返回-1表示读取到了文件末尾EOF(EOF:End Of File)! 每次读取后自动移动文件指针, 准备下次读取。

  1. read(byte[] d)方法

RandomAccessFile提供了一个可以从文件中批量读取字节的方法:

int read(byte[] b)

该方法会从文件中尝试最多读取给定数组的总长度的字节量,并从给定的字节数组第一个位置开始,将读取到的字节顺序存放至数组中,返回值为实际读取到的字节量 。

  1. write(int d)方法

RandomAccessFile提供了一个可以向文件中写出字节的方法:

void write(int d)

该方法会根据当前指针所在位置处写入一个字节,是将参数int的”低8位”写出。

  1. write(byte[] d)方法

RandomAccessFile提供了一个可以向文件中写出一组字节的方法:

void write(byte[] d)

该方法会根据当前指针所在位置处连续写出给定数组中的所有字节,与该方法相似的还有一个常用方法:

void write(byte[] d,int offset,int len)

该方法会根据当前指针所在位置处连续写出给定数组中的部分字节,这个部分是从数组的offset处开始,连续len个字节。

offset + len < 数组的长度

  1. close方法

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

void close()

  1. seek方法

将文件指针定位到pos的位置

void seek(long pos)

  1. getFilePointer方法
    返回文件记录指针的当前位置

long getFilePointer()

RandomAccessFile使用实例

首先来看一下随机读写文件的存储方式,用RandomAccessFile类写入的数据一般都是按照ASCII字符的形式保存在文件 中,即以字节的形式存储,字节是计算机存储设备贬值的最小单元。
Java IO ——RandomAccessFile_第1张图片

当我们按照顺讯存放时,读取的时候也要按顺序读取,不然会报错。
如下图就是依次写入int,byte,double,int,byte,short数据时,在文件中的存放。文件指针会随着数据的写入按照写入后移。
image
特殊的数据读取
字符串读readUTF()和字符串写writeUTF(String str)

        RandomAccessFile access = new RandomAccessFile("test", "rw");
        access.writeUTF("你好");    //以utf-8格式写入数据
        access.writeUTF("朋友"); //以utf-8格式写入数据
        access.close();

        access = new RandomAccessFile("test", "r");
        System.out.println(access.readUTF());
        System.out.println(access.readUTF());
		access.close();

文档中的结构
image
image
可以看到在汉字的前面有一些字符,其实就是2个字节的标记字符串长度的ASCII编码

按顺序跳过内容,进行输出

 RandomAccessFile raf = new RandomAccessFile("fileTest", "rw");
        raf.writeInt(20);
        raf.writeShort(888);
        raf.writeUTF("张三李四");
        raf.close();

        raf = new RandomAccessFile("fileTest", "r");
        System.out.println(raf.readInt());
        raf.skipBytes(2);
//        System.out.println(raf.readShort());
        System.out.println(raf.readUTF());
		raf.close();
		
		//结果
	20
       张三李四

多线程文件操作

注意这里使用的是write(string.getBytes)进行写入。

  public static void thread() throws IOException {
        RandomAccessFile raf = new RandomAccessFile("E://abc.txt", "rw");
        raf.setLength(1024 * 1024);
        raf.close();
        String s1 = "我是第一个字符串";
        String s2 = "我是第二个字符串";
        String s3 = "the third String";
        String s4 = "the fourth string";
        String s5 = "the fifth string";

        //利用多线程同时写入一个文件
        new FileWriteThread(10 * 1, s1.getBytes()).start();
        new FileWriteThread(20 * 2, s2.getBytes()).start();
        new FileWriteThread(30 * 3, s3.getBytes()).start();
        new FileWriteThread(40 * 4, s4.getBytes()).start();
        new FileWriteThread(50 * 5, s5.getBytes()).start();
    }

    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("E://sb.txt", "rw");
                raf.seek(skip);
                raf.write(content);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

如果文件中已存在中文字符,然后seek选择的位置刚好会覆盖部分中文字符串,那么就会出现乱码现象。

读取文件中的内容,为了编码中文乱码出现,需要将编码转换成utf-8编码

RandomAccessFile file = new RandomAccessFile("E://sb.txt", "r");
        //在Windows下raf会默认编码成8859_1
        String line = null;
        while ((line = file.readLine()) != null) {
            System.out.println(new String(line.getBytes("ISO-8859-1"), "utf-8"));
        }

总结
RandomAccessFile 使用非常简单,主要应用于随机读写。
我们需要重点关注的内容就是 RandomAccessFile是以字节的形式进行存储的,所以对于中文字符串的读写要非常注意编码方式,尽量避免乱码现象。

你可能感兴趣的:(Java基础知识)