Java 日看一类(50)之IO包中的RandomAccessFile

该类完成了DataInputDataOutputCloseable接口

引入了如下包

import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;




该类的类头注释如下:

/**
 * Instances of this class support both reading and writing to a
 * random access file. A random access file behaves like a large
 * array of bytes stored in the file system. There is a kind of cursor,
 * or index into the implied array, called the <em>file pointer</em>;
 * input operations read bytes starting at the file pointer and advance
 * the file pointer past the bytes read. If the random access file is
 * created in read/write mode, then output operations are also available;
 * output operations write bytes starting at the file pointer and advance
 * the file pointer past the bytes written. Output operations that write
 * past the current end of the implied array cause the array to be
 * extended. The file pointer can be read by the
 * {@code getFilePointer} method and set by the {@code seek}
 * method.
 * <p>
 * It is generally true of all the reading routines in this class that
 * if end-of-file is reached before the desired number of bytes has been
 * read, an {@code EOFException} (which is a kind of
 * {@code IOException}) is thrown. If any byte cannot be read for
 * any reason other than end-of-file, an {@code IOException} other
 * than {@code EOFException} is thrown. In particular, an
 * {@code IOException} may be thrown if the stream has been closed.
 *
 * @author  unascribed
 * @since   JDK1.0
 */

大意如下:

该类实例支持读取和写入随机访问文件

随机访问文件的操作类似于储存在文件系统中的大型字节数组

存在一种光标或索引指向这个数组,该类光标或者索引叫做文件指针

输入操作从文件指针出开始读取数据并且会修改文件指针到刚刚读取过的位置

如果随机访问文件在读或者写模式下创建,输出操作均是有效的。

输出操作从文件指针出开始写出数据,并且会修改文件指针到刚刚写出的位置

写出到该数组当前末尾后的数据会导致该数组延长

文件指针可以通过getFilePointer获取,通过seek方法设置

一般情况下,常规的读取操作都是正确的

如果在读取够要求读取的数据量前读取到文件末尾,则会抛出EOFException

如果一些 byte因为文件结束以外的原因而无法读取的话,会抛出IOException

尤其是当流关闭后要求读取情况下会抛出IOException




该类含有如下的成员变量:

文件描述符

private FileDescriptor fd;

文件操作通道

private FileChannel channel = null;

读写权限

private boolean rw;

文件路径

private final String path;

关闭锁

private Object closeLock = new Object();

流关闭情况

private volatile boolean closed = false;

常量声明

private static final int O_RDONLY = 1;//只读
private static final int O_RDWR =   2;//读写
private static final int O_SYNC =   4;//读写且同步更新底层存储设备和元数据
private static final int O_DSYNC =  8;//读写且同步更新底层存储设备




该类含有如下的成员方法:

构造函数(给出路径和操作类型

public RandomAccessFile(String name, String mode)
    throws FileNotFoundException
{
    this(name != null ? new File(name) : null, mode);
}

构造函数(给出文件和操作类型

public RandomAccessFile(File file, String mode)
    throws FileNotFoundException
{
    String name = (file != null ? file.getPath() : null);
    int imode = -1;
    if (mode.equals("r"))
        imode = O_RDONLY;
    else if (mode.startsWith("rw")) {
        imode = O_RDWR;
        rw = true;
        if (mode.length() > 2) {
            if (mode.equals("rws"))
                imode |= O_SYNC;
            else if (mode.equals("rwd"))
                imode |= O_DSYNC;
            else
                imode = -1;//无有效操作类型
        }
    }
    if (imode < 0)
        throw new IllegalArgumentException("Illegal mode \"" + mode
                                           + "\" must be one of "
                                           + "\"r\", \"rw\", \"rws\","
                                           + " or \"rwd\"");//异常参数
    SecurityManager security = System.getSecurityManager();//获得安全检测器
    if (security != null) {
        security.checkRead(name);//检测文件是否可读取
        if (rw) {
            security.checkWrite(name);//检测文件是否可写入
        }
    }
    if (name == null) {
        throw new NullPointerException();
    }
    if (file.isInvalid()) {//文件无效
        throw new FileNotFoundException("Invalid file path");
    }
    fd = new FileDescriptor();
    fd.attach(this);//文件描述符绑定自身
    path = name;
    open(name, imode);//以特定模式打开文件
}

获得当前类的文件描述符

public final FileDescriptor getFD() throws IOException {
    if (fd != null) {
        return fd;
    }
    throw new IOException();
}

获得该文件的文件操作管道(如果多个操作打开同一文件,获得文件管道是相同的

public final FileChannel getChannel() {
    synchronized (this) {
        if (channel == null) {
            channel = FileChannelImpl.open(fd, path, true, rw, this);
        }
        return channel;
    }
}

打开文件(native很尴尬

private native void open0(String name, int mode)
    throws FileNotFoundException;

打开文件(调用open0

private void open(String name, int mode)
    throws FileNotFoundException {
    open0(name, mode);
}

从文件中读取出一个byte

public int read() throws IOException {
    return read0();
}

从文件中读取出一个byte

private native int read0() throws IOException;

从文件中读出一个byte数组

private native int readBytes(byte b[], int off, int len) throws IOException;

从文件中读出byte数组

public int read(byte b[], int off, int len) throws IOException {
    return readBytes(b, off, len);
}

从文件中读取数据将数组填满

public int read(byte b[]) throws IOException {
    return readBytes(b, 0, b.length);
}

从文件中读取数据将数组填满

public final void readFully(byte b[]) throws IOException {
    readFully(b, 0, b.length);
}

从文件中读取数据将数组部分填充

public final void readFully(byte b[], int off, int len) throws IOException {
    int n = 0;
    do {
        int count = this.read(b, off + n, len - n);//count为实际读入的数据量
        if (count < 0)
            throw new EOFException();
        n += count;
    } while (n < len);
}

跳过n个数据进行读取

public int skipBytes(int n) throws IOException {
    long pos;//标志位,文件指针
    long len;//文件长度
    long newpos;//偏移后指针

    if (n <= 0) {
        return 0;
    }
    pos = getFilePointer();
    len = length();
    newpos = pos + n;
    if (newpos > len) {//如果偏移后指针超出文件长度,则设置为文件末尾
        newpos = len;
    }
    seek(newpos);

    /* return the actual number of bytes skipped */
    return (int) (newpos - pos);//返回实际跳过数据量
}

写出单个字节

public void write(int b) throws IOException {
    write0(b);
}

写出单个字节

private native void write0(int b) throws IOException;

写出字节数组

private native void writeBytes(byte b[], int off, int len) throws IOException;

写出字节数组

public void write(byte b[]) throws IOException {
    writeBytes(b, 0, b.length);
}

写出字节数组

public void write(byte b[], int off, int len) throws IOException {
    writeBytes(b, off, len);
}

获得文件内操作指针

public native long getFilePointer() throws IOException;

设置文件操作指针(总感觉应该在加一个超出文件长度的检测,可能native方法里有

public void seek(long pos) throws IOException {
    if (pos < 0) {
        throw new IOException("Negative seek offset");
    } else {
        seek0(pos);
    }
}

设置文件操作指针

private native void seek0(long pos) throws IOException;

返回文件长度

public native long length() throws IOException;

设置文件长度

public native void setLength(long newLength) throws IOException;

关闭文件流(并释放相应资源

public void close() throws IOException {
    synchronized (closeLock) {
        if (closed) {
            return;
        }
        closed = true;
    }
    if (channel != null) {
        channel.close();
    }

    fd.closeAll(new Closeable() {//这个写法很独特,创建了接口的实例并直接完成方法(虽然这个传入参数目前没看出来有啥用
        public void close() throws IOException {
           close0();
       }
    });
}

读取一个bool类型(读取int,返回bool

public final boolean readBoolean() throws IOException {
    int ch = this.read();
    if (ch < 0)
        throw new EOFException();
    return (ch != 0);
}

读取一个字节(读取int,返回byte

public final byte readByte() throws IOException {
    int ch = this.read();
    if (ch < 0)
        throw new EOFException();
    return (byte)(ch);
}

读取无符号字节型(-128~127变成0~255)

public final int readUnsignedByte() throws IOException {
    int ch = this.read();
    if (ch < 0)
        throw new EOFException();
    return ch;
}

读取短整形(2byte,需要移位

public final short readShort() throws IOException {
    int ch1 = this.read();
    int ch2 = this.read();
    if ((ch1 | ch2) < 0)
        throw new EOFException();
    return (short)((ch1 << 8) + (ch2 << 0));
}

读取无符号短整形

public final int readUnsignedShort() throws IOException {
    int ch1 = this.read();
    int ch2 = this.read();
    if ((ch1 | ch2) < 0)
        throw new EOFException();
    return (ch1 << 8) + (ch2 << 0);
}

读取字符型

public final char readChar() throws IOException {
    int ch1 = this.read();
    int ch2 = this.read();
    if ((ch1 | ch2) < 0)
        throw new EOFException();
    return (char)((ch1 << 8) + (ch2 << 0));
}

读取整形

public final int readInt() throws IOException {
    int ch1 = this.read();
    int ch2 = this.read();
    int ch3 = this.read();
    int ch4 = this.read();
    if ((ch1 | ch2 | ch3 | ch4) < 0)
        throw new EOFException();
    return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}

读取长整型

public final long readLong() throws IOException {
    return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
}

读取浮点型

public final float readFloat() throws IOException {
    return Float.intBitsToFloat(readInt());
}

读取双精度

public final double readDouble() throws IOException {
    return Double.longBitsToDouble(readLong());
}

读取一行字符串(读取到无数据、换行符或者新行符结束

public final String readLine() throws IOException {
    StringBuffer input = new StringBuffer();
    int c = -1;
    boolean eol = false;

    while (!eol) {
        switch (c = read()) {
        case -1:
        case '\n':
            eol = true;
            break;
        case '\r':
            eol = true;
            long cur = getFilePointer();
            if ((read()) != '\n') {
                seek(cur);
            }
            break;
        default:
            input.append((char)c);
            break;
        }
    }

    if ((c == -1) && (input.length() == 0)) {
        return null;
    }
    return input.toString();
}

读取出的字节进行UTF转码

public final String readUTF() throws IOException {
    return DataInputStream.readUTF(this);
}

写入bool

public final void writeBoolean(boolean v) throws IOException {
    write(v ? 1 : 0);
    //written++;
}

写入byte

public final void writeByte(int v) throws IOException {
    write(v);
    //written++;
}

写入短整型

public final void writeShort(int v) throws IOException {
    write((v >>> 8) & 0xFF);
    write((v >>> 0) & 0xFF);
    //written += 2;
}

写入字符型

public final void writeChar(int v) throws IOException {
    write((v >>> 8) & 0xFF);
    write((v >>> 0) & 0xFF);
    //written += 2;
}

写入整型

public final void writeInt(int v) throws IOException {
    write((v >>> 24) & 0xFF);
    write((v >>> 16) & 0xFF);
    write((v >>>  8) & 0xFF);
    write((v >>>  0) & 0xFF);
    //written += 4;
}

写入长整型

public final void writeLong(long v) throws IOException {
    write((int)(v >>> 56) & 0xFF);
    write((int)(v >>> 48) & 0xFF);
    write((int)(v >>> 40) & 0xFF);
    write((int)(v >>> 32) & 0xFF);
    write((int)(v >>> 24) & 0xFF);
    write((int)(v >>> 16) & 0xFF);
    write((int)(v >>>  8) & 0xFF);
    write((int)(v >>>  0) & 0xFF);
    //written += 8;
}

写入浮点型

public final void writeFloat(float v) throws IOException {
    writeInt(Float.floatToIntBits(v));
}

写入双精度

public final void writeDouble(double v) throws IOException {
    writeLong(Double.doubleToLongBits(v));
}
写入字符串(字节写入
public final void writeBytes(String s) throws IOException {
    int len = s.length();
    byte[] b = new byte[len];
    s.getBytes(0, len, b, 0);
    writeBytes(b, 0, len);
}

写入字符串(字符写入

public final void writeChars(String s) throws IOException {
    int clen = s.length();
    int blen = 2*clen;
    byte[] b = new byte[blen];
    char[] c = new char[clen];
    s.getChars(0, clen, c, 0);
    for (int i = 0, j = 0; i < clen; i++) {
        b[j++] = (byte)(c[i] >>> 8);
        b[j++] = (byte)(c[i] >>> 0);
    }
    writeBytes(b, 0, blen);
}

写入UTF格式的字符串

public final void writeUTF(String str) throws IOException {
    DataOutputStream.writeUTF(str, this);
}

private static native void initIDs();

private native void close0() throws IOException;

static {
    initIDs();
}




读取方式读取的元数据都是字节,读取出的不同数据类型都是对字节进行移位以及其他操作转换而成的,写入操作也是同理,写入的数据类型也有很多,但是最终都是转化成字节再写入到文件中的。该类的常量声明主要针对于FileChannel,在此不过多赘述。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值