java IO笔记(RandomAccessFile)
来源:互联网 发布:sftp用的什么端口 编辑:程序博客网 时间:2024/06/06 07:38
本篇讲述的内容是java io中的RandomAccessFile。
RandomAccessFile是java io体系中提供给我们的一种文件访问类,它自己同时包含了读写功能,当然它最大的特点是可以自由访问文件中的位置,无需从头开始访问,下面先贴上RandomAccessFile的源码,通过源码对其进行学习。
package java.io;import java.nio.channels.FileChannel;import sun.nio.ch.FileChannelImpl;public class RandomAccessFile implements DataOutput, DataInput, Closeable { //声明了一个文件描述符的句柄。 private FileDescriptor fd; //声明了一个文件通道的句柄,并将其指向null。 private FileChannel channel = null; //定义了一个boolean型变量rw,用于表示文件的读写权限。 private boolean rw; //定义了一个String类型的变量path,用于接收 private final String path; //定义了一个Object对象,为后面close方法中的同步操作提供锁对象。 private Object closeLock = new Object(); //定义了一个boolean型变量closed,用于表示当前流是否关闭,用volatile关键字修饰,保证了其改变的可见性。 private volatile boolean closed = false; //定义了4个常量,分别表示了RandomAccessFile的4种读写模式。 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;//同步的读写模式,具备读写模式的所有特性,当文件内容改变时,会立马同步写入到底层存储设备中。 /** * 带两个参数的构造方法,第一个参数为String类型,表示需要进行操作的文件路径名,第二个参数为String类型,表示以什么模式打开文件(四种模式,r,rw,rws, * rwd)。内部实质是继续调用后面的构造函数RandomAccessFile(File file, String mode)。 */ public RandomAccessFile(String name, String mode) throws FileNotFoundException { this(name != null ? new File(name) : null, mode); } /** * 带两个参数的构造方法,第一个参数为File类型,表示要进行操作的文件对象,第二个参数为String类型,表示打开文件的模式。 */ public RandomAccessFile(File file, String mode) throws FileNotFoundException {// 定义了一个String类型变量name用于接收操作文件的路径名,如果文件为null,则name赋值为null。 String name = (file != null ? file.getPath() : null);// 定义了一个int型变量imode,表示打开文件的模式状态,初始化默认为-1。 int imode = -1;// 对传入的参数mode进行匹配,给imode,rw赋值,表示读写权限。 if (mode.equals("r")) //"r",只读模式。 imode = O_RDONLY; else if (mode.startsWith("rw")) { //"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; } }//如果imode<0(其实就是等于-1),那么抛出相应的异常,提示传入的读写模式是非法的,并告知是要填四种合法模式中的一种。 if (imode < 0) throw new IllegalArgumentException("Illegal mode \"" + mode + "\" must be one of " + "\"r\", \"rw\", \"rws\"," + " or \"rwd\"");//获得java的安全管理器,根据rw的状态监测文件的读写权限。 SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); if (rw) { security.checkWrite(name); } } //如果name为null,抛出相应的异常,NullPointerException。 if (name == null) { throw new NullPointerException(); }//如果file.isInvalid的值为true,则表示file对象不合法,抛出相应的异常,FileNotFoundException。 if (file.isInvalid()) { throw new FileNotFoundException("Invalid file path"); }//将声明的句柄指向一个新建的文件描述符对象,并将本类对象依附在该文件描述符上。为path赋值,然后调用open方法根据指定路径和模式打开文件。 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 open(String name, int mode) throws FileNotFoundException; //此处开始是RandomAccessFile的读操作 /** * 定义了一个read方法,每次从文件中读取一个字节的内容,并以int型返回读取的数据。内部实质是调用native方法read0()。 */ public int read() throws IOException { return read0(); } /** * 定义了一个native方法read0,用于每次从文件中读取一个字节的内容,并以int型将读取的数据返回。 */ private native int read0() throws IOException; /** * 定义了一个native方法readBytes方法,一次可以读取多个字节,并将读取的数据放入传入的字节数组当中,最终返回实际读取到的字节个数。 */ private native int readBytes(byte b[], int off, int len) throws IOException; /** * 定义了一个带三个参数的read方法,第一个参数为一个byte型数组,用于存放读取的字节内容,第二和第三个参数都是一个int型数值,分别表示了读取的起点以及读 * 取的长度。内部实质上是调用native方法readBytes方法来读取数据。 */ public int read(byte b[], int off, int len) throws IOException { return readBytes(b, off, len); } /** * 定义了一个带一个参数的read方法,传入的参数为一个byte型数组,用于存放读取的字节数据,内部实质上是调用native方法readBytes方法,起点为0长度为传入的 * 数组容量。 */ public int read(byte b[]) throws IOException { return readBytes(b, 0, b.length); } /** * 定义了一个readFully方法,每次读取多个字节数据,传入的参数为一个byte型数组。内部实质是调用之后的带三个参数的readFully方法,只有当数组存满或者文件 * 结尾或者抛出异常时才停止。 */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } /** * 定义了一个带三个参数的readFully方法,第一个参数为一个byte型数组,用于存放读取的字节数据,第二和第三个参数为int型数据,分别为读取的起点和读取的长度 * 。当数组存满或者文件结尾或者抛出异常时才停止。 */ public final void readFully(byte b[], int off, int len) throws IOException { int n = 0;// 通过一个循环,调用read方法来进行文件的读取,直到读取指定的长度。 do { int count = this.read(b, off + n, len - n); if (count < 0) throw new EOFException(); n += count; } while (n < len); } /** * 定义了一个skipBytes方法,该方法用于跳过指定的字节数,传入的参数为一个int型数值,为需要跳过的字节数,最后返回实际跳过的字节数。 */ public int skipBytes(int n) throws IOException { //声明了3个long型变量,pos为当前读取的字节位置,len为文件的总长度,newpos表示跳过后指定字节后的读取读取位置。 long pos; long len; long newpos;//如果传入的参数小于等于零,则返回零,表示没有跳过任何字节的数据。 if (n <= 0) { return 0; } //通过getFilePointer方法,获取当前文件读取的索引位置。通过length方法获取文件的总长度。为newpos赋值,为当前位置加上跳过的字节数。 pos = getFilePointer(); len = length(); newpos = pos + n;//如果newpos大于文件总长度,那么newpos置位到文件尾部。 if (newpos > len) { newpos = len; }//调用seek方法,跳至newpos处。最终返回newpos-pos的值,表示实际跳过的字节数。 seek(newpos); return (int) (newpos - pos); } //此处开始是RandomAccessFile的写操作。 /** * 定义了一个write方法,每次写入一个字节的数据,传入的参数为一个int型值,即要写入的数据。内部实质是调用native方法write0来写入数据。 */ public void write(int b) throws IOException { write0(b); } //定义了一个native方法write0,传入的参数为int型数据,每次写入一个字节的数据。 private native void write0(int b) throws IOException; /** * 定义了一个native方法writeBytes,每次写入多个字节的数据,有三个参数,第一个参数为一个byte型数组,里面存放了要写入的数据,第二和第三个参数都是int型 * 数据,分别表示了写入的起点以及写入的长度。 */ private native void writeBytes(byte b[], int off, int len) throws IOException; /** * 定义了一个write方法,每次写入多个字节的数据。传入的参数为一个byte型数组,里面存放了要写入的数据,内部实质调用了native方法writeBytes来写入数据。 */ public void write(byte b[]) throws IOException { writeBytes(b, 0, b.length); } /** * 定义了一个带3个参数的write方法,每次写入多个字节的数据。第一个参数为一个byte型数组,里面存放了要写入的字节数据,第二和第三个参数为int型数据,分别 * 表示了写入的起点以及写入的长度。内部实质是调用native方法writeBytes来写入数据。 */ public void write(byte b[], int off, int len) throws IOException { writeBytes(b, off, len); } //RandomAccessFile独有的随机读取操作。 /** * 定义了一个native方法getFilePointer,该方法用来获取当前文件读取的位置。 */ public native long getFilePointer() throws IOException; /** * 定义了一个seek方法,用于跳过指定字节长度的数据。传入的参数为一个long型数据,代表着要跳过的字节数。 */ public void seek(long pos) throws IOException {//对传入的参数进行安全监测,如果其小于零,则抛出相应的异常。 if (pos < 0) { throw new IOException("Negative seek offset"); } else { //调用native方法seek0,用来跳过指定字节数量的数据。 seek0(pos); } } //定义了一个native方法seek0,用于跳过指定字节长度的数据,传入的参数为一个long型数据,其表示要跳过的字节长度。 private native void seek0(long pos) throws IOException; /** * 定义了一个native方法length,用于获得文件的总长度 */ public native long length() throws IOException; /** * 定义了一个native方法setLength,用于重新设定文件的长度。 */ public native void setLength(long newLength) throws IOException; /** * 定义了一个close方法,用于关闭流及其相关联的系统资源。 */ 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(); } }); } //一些从DataInputStream/DataOuputStream中读写方法,方便对不同类型的数据进行读写。 /** * 读取一个boolean型的数据,工作原理其实就是读取一个字节的数据,比较其是否等于0,因为0表示false,非0表示true。 */ public final boolean readBoolean() throws IOException { int ch = this.read(); if (ch < 0) throw new EOFException(); return (ch != 0); } /** * 读取一个字节的数据,工作原理其实就是调用read方法读取一个字节的数据,然后转换成byte型数据。 */ public final byte readByte() throws IOException { int ch = this.read(); if (ch < 0) throw new EOFException(); return (byte)(ch); } /** * 读取一个不带符号字节数,工作原理就是直接调用read方法并返回。 */ public final int readUnsignedByte() throws IOException { int ch = this.read(); if (ch < 0) throw new EOFException(); return ch; } /** * 读取一个short型数据,工作原理其实就是调用两次read方法,读取的数据作为short型数据的高八位和低八位,然后返回该数据。 */ 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)); } /** * 读取一个不带符号的short型数据,工作原理其实就是调用两次read方法,读取的数据作为short型数据的高八位和低八位,然后返回改数据。 */ 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); } /** * 读取一个字符,工作原理就是调用两次read方法,读取的数据作为char型数据的高八位和低八位,然后将其返回。 */ 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)); } /** * 读取一个int型数据,调用4次read方法,读取的数据代表着int型数据高位到地位,最终返回一个int型数据 */ 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)); } /** * 读取一个long型数据,本质是调用了两次readInt方法,读取的数据作为long型数据的高32位和低32位。 */ public final long readLong() throws IOException { return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL); } /** * 读取一个Float型数据,原理是通过readInt读取一个int型数据,然后将其转换为Float型数据并返回。 */ public final float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } /** * 读取一个Double型数据,原理是通过readLong读取一个lo ng型数据,然后将其转换为Double型数据并返回。 */ public final double readDouble() throws IOException { return Double.long BitsToDouble(readLong()); } /** * 一次读取一行数据,并将读取到的数据返回。 */ public final String readLine() throws IOException {//创建了一个StringBuffer对象,用于接收读取的数据。 StringBuffer input = new StringBuffer();//声明了一个int型变量c,用于接收读取的数据,声明了一个boolean型变量eol,表明是否读取到了换行符。 int c = -1; boolean eol = false; //通过一个循环来不断读取数据。 while (!eol) { switch (c = read()) { case -1://返回-1表示文件已经读取完毕。 case '\n'://返回'\n',表示读到换行符,此时将eol置为true,跳出循环。 eol = true; break; case '\r'://返回'\r',将eol置为true,因为平台换行符不同,向后读取看是否有'\n',如果没有则返回'\r'处,然后跳出循环 eol = true; long cur = getFilePointer(); if ((read()) != '\n') { seek(cur); } break; default://每次操作向input中添加读取的内容。 input.append((char)c); break; } }//如果没有读取到任何数据,则返回null。最终将input转化成String类型然后返回。 if ((c == -1) && (input.length() == 0)) { return null; } return input.toString(); } /** * 定义了一个readUTF的方法,实质是直接调用DataInputStream的readUTF方法。 */ public final String readUTF() throws IOException { return DataInputStream.readUTF(this); } /** * 定义了一个写入Bollean型数据的方法。原理是根据数据是否等于0来决定true和false。 */ public final void writeBoolean(boolean v) throws IOException { write(v ? 1 : 0); } /** * 每次写入一个字节的数据。 */ public final void writeByte(int v) throws IOException { write(v); } /** * 每次写入一个short型数据。实际上是通过两次write方法,每次写入一个字节的数据,分别写入short型数据高八位和低八位。 */ public final void writeShort(int v) throws IOException { write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } /** * 每次写入一个char型数据。实际上是通过两次write方法,每次写入一个字节的数据,分别写入char型数据高八位和低八位。 */ public final void writeChar(int v) throws IOException { write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } /** * 每次写入一个int型数据。实际上是通过4次write方法,每次写入一个字节的数据,从最高位开始,每八位一组依次写入。 */ public final void writeInt(int v) throws IOException { write((v >>> 24) & 0xFF); write((v >>> 16) & 0xFF); write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); } /** * 每次写入一个long型数据。实际上是通过8次write方法,每次写入一个字节的数据,从最高位开始,每八位一组依次写入。 */ 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); } /** * 每次写入一个Float型数据。实际上是先将float型数据装换成int型数据,然后调用writeInt方法写入数据。 */ public final void writeFloat(float v) throws IOException { writeInt(Float.floatToIntBits(v)); } /** * 每次写入一个Double型数据。实际上是先将double型数据转换成long型数据,然后调用writeLong方法写入数据。 */ public final void writeDouble(double v) throws IOException { writeLong(Double.doubleToLongBits(v)); } /** * 每次写入一个字符串,实质上是先将字符串转换为字节数组,然后调用writeBytes方法写入。 */ @SuppressWarnings("deprecation") 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); } /** * 每次写入一个字符串,实质上是先将字符串转换成字符数组,在将字符数组转化成字节数组,然后调用writeBytes方法写入。 */ 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字符串,实质上是直接调用DataOutputStream的writeUTF方法。 */ 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(); }}
通过以上对源码的简单分析,我们对RandomAccessFile有了初步的认识,它自身就包含了读写功能,同时具有随机读取这一大亮点。下面用一个简单的例子来简单展示一下它的用法。
package RandomIO;import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;public class RandomIOTest1 {public static void main(String[] args) {final File source = new File("./src/file/test.avi");final File target = new File("./src/file/testcopy.avi");int ThreadNum = (int) Math.ceil(Math.ceil((double) source.length() / 1024 / 1024 / 10));for (int i = 0; i < ThreadNum; i++) {Thread thread = new Thread(new MyRunnable(i, source, target));thread.start();}}}class MyRunnable implements Runnable {private int num;private File source;private File target;MyRunnable(int num, File source, File target) {this.num = num;this.source = source;this.target = target;}@Overridepublic void run() {try (RandomAccessFile sourceFile = new RandomAccessFile(source, "rw");RandomAccessFile targetFile = new RandomAccessFile(target, "rw");) {System.out.println("线程" + num + "启动");sourceFile.seek(num * 1024 * 1024 * 10);targetFile.seek(num * 1024 * 1024 * 10);byte[] buffer = null;if ((sourceFile.length() - sourceFile.getFilePointer()) < 1024 * 1024 * 10) {buffer = new byte[(int) (sourceFile.length() - sourceFile.getFilePointer())];} else {buffer = new byte[1024 * 1024 * 10];}sourceFile.read(buffer);targetFile.write(buffer);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}System.out.println("线程" + num + "复制结束");}}该例子使用了多线程同时复制一个文件,每个线程拷贝10MB的数据,运行上述代码后可以在指定路径下看到拷贝成功的文件,笔者拷贝了一个100多MB的小视频,拷贝的视频可以正常播放,效果图如下:
RandomAccessFile类的功能十分强大,但人无完人,它也有着一定的缺陷,从源码中可以看出,RandomAccessFile类在进行读写操作时,都是直接与底层介质进行数据传递的,即使是读写一个字节的数据,也必须进行一次I/O操作,这样就大大降低了其工作的效率。在前面如BufferedReader/BufferedWriter的学习中,我们了解了我们可以通过内置一个数据缓存区来提升读写效率,RandomAccessFile也同样可以这样操作,我们可以完全重构一个属于自己的带缓存的BufferedRandomAccessFile类。
package RandomIO;import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;import java.util.Arrays;public class BufferedRandomAccessFile1 extends RandomAccessFile {private static final int Default_Buffer_Size = 1024 * 8;private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;private static final long BuffMask_ = ~(((long) Default_Buffer_Size) - 1L);//表示缓存区是否有未flush的数据。private boolean hasDatas; //表示是否进行同步操作,将缓存内容flush。private boolean syncNeeded_;//当前操作文件的索引位置(包括在缓存区中)。private long cPos = 0L;//磁盘上操作文件的索引位置(存储介质中)。private long diskPos_ = 0L; private long lo_, hi_ = 0L; private long maxHi_ = (long)Default_Buffer_Size; //是否到了文件结束部分。private boolean isEOF; //内置的一个数组缓存区,默认大小是8k。private byte[] buffer;public BufferedRandomAccessFile1(File file, String mode) throws IOException {this(file, mode, Default_Buffer_Size);}public BufferedRandomAccessFile1(String name, String mode)throws IOException {this(name, mode, Default_Buffer_Size);}public BufferedRandomAccessFile1(File file, String mode, int size)throws IOException {super(file, mode);init(size);}public BufferedRandomAccessFile1(String name, String mode, int size)throws FileNotFoundException {super(name, mode);init(size);}//对内置缓存区进行初始化private void init(int size) {if (size < Default_Buffer_Size) {size = Default_Buffer_Size;} else if (size > MAX_BUFFER_SIZE) {size = MAX_BUFFER_SIZE;}buffer = new byte[size];}//将缓存区中的数据同步写出到存储介质中。public void sync() throws IOException {if (syncNeeded_) {//将内置缓存区中的数据写入flush();//将文件通道内未写入磁盘的数据强制写入到磁盘中,传入的参数表示是否将文件元信息写入到磁盘之上。getChannel().force(true);syncNeeded_ = false;}}// close前将缓存区刷新一次防止缓存区中有未写入的数据,然后将缓存区置为null,调用父类的close方法释放资源。public void close() throws IOException {this.flush();this.buffer = null;super.close();}//将缓存区中内容写入存储介质中public void flush() throws IOException {this.flushBuffer();}//将缓存中内容写入存储介质之中private void flushBuffer() throws IOException {if (hasDatas) {if (diskPos_ != lo_)super.seek(lo_);int len = (int) (cPos - lo_);super.write(buffer, 0, len);diskPos_ = cPos;hasDatas = false;}}//向缓存区中填充数据。返回实际填充了多少字节的数据。private int fillBuffer() throws IOException {int nextChar = 0;int nChars = buffer.length;//通过一个循环,向缓存区中填充数据,直至将缓存区填满或者文件读到末尾。while (nChars > 0) {int n = super.read(buffer, nextChar, nChars);if (n < 0)break;nextChar += n;nChars -= n;}if ((nextChar < 0) && (isEOF = (nextChar < buffer.length))) {//将为缓存区中未填充到的部分全用-1初始化。Arrays.fill(buffer, nextChar, buffer.length, (byte) 0xff);}diskPos_ += nextChar;return nextChar;}//跳过指定的字节数public void seek(long pos) throws IOException {if (pos >= hi_ || pos < lo_) {flushBuffer();lo_ = pos & BuffMask_; maxHi_ = lo_ + (long) buffer.length;if (diskPos_ != lo_) {super.seek(lo_);diskPos_ = lo_;}int n = fillBuffer();hi_ = lo_ + (long) n;} else {if (pos < cPos) {flushBuffer();}}cPos = pos;}public long getFilePointer() {return cPos;}public long length() throws IOException {return Math.max(cPos, super.length());}public int read() throws IOException {if (cPos >= hi_) {if (isEOF)return -1;seek(cPos);if (cPos == hi_)return -1;}byte res = buffer[(int) (cPos - lo_)];cPos++;return ((int) res) & 0xFF; }public int read(byte[] b) throws IOException {return read(b, 0, b.length);}public int read(byte[] b, int off, int len) throws IOException {if (cPos >= hi_) {if (isEOF)return -1;seek(cPos);if (cPos == hi_)return -1;}len = Math.min(len, (int) (hi_ - cPos));int buffOff = (int) (cPos - lo_);System.arraycopy(buffer, buffOff, b, off, len);cPos += len;return len;}public void write(int b) throws IOException {if (cPos >= hi_) {if (isEOF && hi_ < maxHi_) {hi_++;} else {seek(cPos);if (cPos == hi_) {hi_++;}}}buffer[(int) (cPos - lo_)] = (byte) b;cPos++;hasDatas = true;syncNeeded_ = true;}public void write(byte[] b) throws IOException {write(b, 0, b.length);}public void write(byte[] b, int off, int len) throws IOException {while (len > 0) {int n = writeAtMost(b, off, len);off += n;len -= n;hasDatas = true;syncNeeded_ = true;}}private int writeAtMost(byte[] b, int off, int len) throws IOException {if (cPos >= hi_) {if (isEOF && hi_ < maxHi_) {hi_ = maxHi_;} else {seek(cPos);if (cPos == hi_) {hi_ = maxHi_;}}}len = Math.min(len, (int) (hi_ - cPos));int buffOff = (int) (cPos - lo_);System.arraycopy(b, off, buffer, buffOff, len);cPos += len;return len;}}最终,用一个小例子来验证其工作效率,我们将比较RandomAccessFile,BufferedRandomAccessFile,BufferedInput/OutputStream的效率。
package RandomIO;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.RandomAccessFile;public class RandomIOTest2 {public static void main(String[] args) {long startTime;long endTime;File source = new File("./src/file/test.avi");File target = new File("./src/file/testcopy.avi");byte[] buffer = new byte[1024];startTime = System.currentTimeMillis();int len;try (RandomAccessFile sourceFile = new RandomAccessFile(source, "rw");RandomAccessFile targetFile = new RandomAccessFile(target, "rw")) {while ((len = sourceFile.read(buffer)) != -1) {targetFile.write(buffer, 0, len);}endTime = System.currentTimeMillis();System.out.println("RandomAccessFile拷贝耗时" + (endTime - startTime)+ "ms");} catch (Exception e) {}startTime = System.currentTimeMillis();try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target));) {while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);}endTime = System.currentTimeMillis();System.out.println("BufferedInputStream/BuffedOutputStream拷贝耗时"+ (endTime - startTime) + "ms");} catch (Exception e) {}startTime = System.currentTimeMillis();try (BufferedRandomAccessFile1 sourceFile = new BufferedRandomAccessFile1(source, "rw");BufferedRandomAccessFile1 targetFile = new BufferedRandomAccessFile1(target, "rw")) {while ((len = sourceFile.read(buffer)) != -1) {targetFile.write(buffer, 0, len);}endTime = System.currentTimeMillis();System.out.println("BufferedRandomAccessFile1拷贝耗时" + (endTime - startTime)+ "ms");} catch (Exception e) {}}}执行上述代码,可以看到以下输出结果:
从输出中可以看出,RandomAccessFile的效率确实很低,但加上缓存后,工作效率立马提升。
以上为本篇内容。
阅读全文
0 0
- java IO笔记(RandomAccessFile)
- java Io RandomAccessFile类 笔记
- Java IO笔记(3)RandomAccessFile
- java.io.RandomAccessFile
- Java.IO.RandomAccessFile
- [java-io]RandomAccessFile
- Java--(IO)之RandomAccessFile
- Java IO-RandomAccessFile
- Java IO--RandomAccessFile类
- Java IO----RandomAccessFile
- Java.io.RandomAccessFile用法
- Java IO-RandomAccessFile类
- java.io.RandomAccessFile
- java.io.RandomAccessFile
- java IO-RandomAccessFile
- 【Java-IO】RandomAccessFile
- 14.Java IO: RandomAccessFile
- java.io.RandomAccessFile
- leetcode 5. Longest Palindromic Substring
- 打印机-顾客进程同步
- IO--打印流
- jQuery基础 | 选择器
- 宏基因组分析教程-Analysis of Metagenomic Data
- java IO笔记(RandomAccessFile)
- 计蒜客 17118 Maximum Flow(2017 ACM-ICPC 亚洲区(西安赛区)网络赛 E)
- SQL Server学习笔记3:数据库中表的插入、删除、修改、合并
- android build system
- 《把时间当作朋友》读书笔记
- 重装系统步骤
- ArrayList源码解析
- 实验吧解题笔记——编程(一)
- POJ 2031 Building a Space Station