Java8 I/O源码-RandomAccessFile

本文介绍了Java8中RandomAccessFile类的用途,它支持对文件的随机读写操作,利用文件指针进行访问。文章讨论了随机访问的实现原理、打开模式以及其与InputStream和OutputStream的区别,并提供了源码阅读的总结,指出其实现了DataOutput和DataInput接口,允许读写Java基本数据类型。
摘要由CSDN通过智能技术生成

今天学习RandomAccessFile。

RandomAccessFile,用来随机访问文件的类。它支持对随机访问文件的读取和写入。这里的随机并不意味着不可控制,而是意味着可以访问文件内容的任意位置。

随机访问文件是如何实现的呢?

随机访问文件是通过“文件指针”来实现的。文件指针可看做指向文件中任意位置的光标或索引。该文件指针可以通过getFilePointer方法读取,通过seek方法设置。输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入文件末尾之后的输出操作导致该数组扩展。

源码太长,放在最后,有兴趣的可以向后看。

demo
import java.io.File;
import java.io.RandomAccessFile;

import org.junit.Test;

import java.io.IOException;

/**
 * RandomAccessFile demo
 */
public class RandomAccessFileTest {
   

    private static final File file = new File("randomAccessFileTest.txt");

    private void prepare() {
        // 若文件存在,则删除该文件。目的是避免干扰。
        if (file.exists())
            file.delete();
    }

    // 测试seek、getFilePointer、length方法。打印结果为
    /**
     * 偏移量的设置超出文件末尾不会改变文件的长度。
     * getFilePointer():54
     * length():54
     * getFilePointer():111111
     * length():54
     * 只有在偏移量的设置超出文件末尾的情况下对文件进行写入才会更改其长度。
     */
    @Test
    public void testSeek() {
        prepare();
        try {
            RandomAccessFile raf = new RandomAccessFile(file, "rw");

            raf.writeChars("abcdefghijklmnopqrstuvwxyz\n");

            System.out.println("偏移量的设置超出文件末尾不会改变文件的长度。");
            System.out.println("getFilePointer():" + raf.getFilePointer());
            System.out.println("length():" + raf.length());
            raf.seek(111111);
            System.out.println("getFilePointer():" + raf.getFilePointer());
            System.out.println("length():" + raf.length());

            System.out.println("只有在偏移量的设置超出文件末尾的情况下对文件进行写入才会更改其长度。");

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

    //测试testSetLength方法。打印结果为
    /**
     * SetLength会改变文件大小,并没有改变下一个要写入的内容的位置。
     * getFilePointer():54
     * length():54
     * getFilePointer():54
     * length():111111
     */
    @Test
    public void testSetLength() {
        prepare();
        try {
            RandomAccessFile raf = new RandomAccessFile(file, "rw");

            raf.writeChars("abcdefghijklmnopqrstuvwxyz\n");

            System.out.println("SetLength会改变文件大小,并没有改变下一个要写入的内容的位置。");
            System.out.println("getFilePointer():" + raf.getFilePointer());
            System.out.println("length():" + raf.length());
            raf.setLength(111111l);
            System.out.println("getFilePointer():" + raf.getFilePointer());
            System.out.println("length():" + raf.length());

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

    /**
     * 向文件中写入内容
     */
    @Test
    public void testWrite() {
        prepare();
        try {
            RandomAccessFile raf = new RandomAccessFile(file, "rw");

            raf.writeChars("abcdefg\n");
            raf.writeBoolean(true);
            raf.writeByte(0x51);
            raf.writeChar('h');
            raf.writeShort(0x3c3c);
            raf.writeInt(0x66);
            raf.writeLong(0x123456789L);
            raf.writeFloat(1.1f);
            raf.writeDouble(1.111);
            raf.writeUTF("潘威威的博客");
            raf.writeChar('\n');
            //追加内容
            raf.seek(raf.length());
            raf.write("追加的内容".getBytes());

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

    //读取文件并打印。打印结果为
    /**
     * readChar():a
     * read(byte[],int,len):
     */
    @Test
    public void testRead() {
        try {
            RandomAccessFile raf = new RandomAccessFile(file, "r");
            System.out.println("readChar():" + raf.readChar());

            raf.skipBytes(2);//跳过两个字节,即跳过了'b'字符

            byte[] buf = new byte[10];
            raf.read(buf, 0, buf.length);
            System.out.println("read(byte[],int,len):" + (new String(buf)));

            raf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
源码

下面是观看源码的总结。

RandomAccessFile并没有继承InputStream或者OutputStream,而是实现了DataOutput和DataInput。这说明它可以操作Java基础数据类型,而且既可读,也可写。

打开文件的访问模式有四种:

  • “r”——以只读方式打开。调用结果对象的任何write方法都将导致抛出IOException。
  • “rw”——打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
  • “rws”——打开以便读取和写入,对于 “rw”,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
  • “rwd”——打开以便读取和写入,对于 “rw”,还要求对文件内容的每个更新都同步写入到底层存储设备。

一般使用前两个模式。

RandomAccessFile中读写Java基本数据类型的方法实现和DataInputStream与DataOutputStream极其相似,可以参考Java8 I/O源码-DataInputStream与DataOutputStream一文了解这些方法的实现。

/**
 * RandomAccessFile并没有继承InputStream或者OutputStream,而是实现了DataOutput和DataInput。
 * 这说明它可以操作Java基础数据类型,而且既可读,也可写。
 * 
 */
public class RandomAccessFile implements DataOutput, DataInput, Closeable {
   

    //文件描述符
    private FileDescriptor fd;
    //文件通道
    private FileChannel channel = null;
    //标识此文件是否既可以读又可以写
    private boolean rw;

    /**
     * 引用文件的路径
     */
    private
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值