java IO笔记(RandomAccessFile)

【Java笔记】IO流-随机存取文件流(RandomAccessFile类) RandomAccessFile 声明在 java . io 包下,但直接继承与 java . lang . Object 类。并且它实现了 DataInput、DataOutput 这两个接口,也就意味着这个类既可以读也可以写 目录 RandomAccessFile的使用 RandomAccessFile实现数据的存取 RandomAccessFile在指定位置插入数据 RandomAccessFile的使用 RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到 阅读详情

本篇讲述的内容是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;
	}

	@Override
	public 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的效率确实很低,但加上缓存后,工作效率立马提升。
以上为本篇内容。

文件读写// "r", "rw", "rws", or "rwd" 文件读写// "r", "rw", "rws", or "rwd" File file = new File("look.txt"); System.out.print("请输入日记内容:"); 立即下载

相关推荐

MuJoCo 关节角速度记录与可视化,监控机械臂运动状态

1. 手动计算关节速度,其中timestep为仿真步长。2. 使用data.qvel直接取得关节速度。

darcsdn 767

RandomAccessFile的writeBytes()方法与write()方法

RandomAccessFile的writeBytes()方法与write()方法@TOC 解决RandomAccessFile向文本文档里写中文总是乱码的问题: 第一种解释: RandomAccessFile rf = null; try { rf = new RandomAccessFile(fileName, “rw”); rf.seek(rf.length()); rf.writeByte...

weixin_43651188的博客 1309

Qt QChart实战:从零打造一个实时温度监控仪表盘(附完整源码)

本文详细介绍了如何使用Qt QChart模块从零构建一个工业级实时温度监控仪表盘。通过实战案例,展示了波形图的绘制、坐标轴配置、数据流模拟等关键技术,并提供了完整的源码实现,帮助开发者快速掌握Qt在数据可视化领域的应用。

weixin_42537919的博客 242

JavaI/O中使用readUTF()报java.io.EOFException暂时解决方案

问题描述练习JavaI/O时自己试着写demo,当使用RandomAccessFile的readUTF()方法时报java.io.EOFException。源码如下: DirList.javapackage com.star.io;import java.io.IOException; import java.io.RandomAccessFile;public class DirList {

zhoucheng05_13的博客 6818

告别手动转换!用腾讯云轻量服务器+QMT插件,5分钟搞定聚宽策略实盘(附完整源码)

本文详细介绍如何利用腾讯云轻量服务器和QMT插件快速实现聚宽策略的自动化实盘部署。通过云端信号中转站解决协议转换、信号缓存等核心问题,5分钟完成服务器配置,并附完整源码实现零改造实盘方案,显著提升量化交易效率。

weixin_28707739的博客 659

比较几款国际主流的电子元器件及物料清单管理软件 – 工具汇总

Arenasolution 老牌的基于云计算物料清单管理软件,bom.com就是他们家的,10天免费试用,功能被分成4个不同的产品, 和传统ERP功能上有重叠,偏向于物流生产规划,一定程度可以取代ERP的生产规划模块,平均价格70美元/月/席位。网页客户端,不支持离线   SiliconExpert 曾经的老牌物料清单管理软件,后被Arrow 收购,14天免费试用,功能被分成4个不同的产品

u012062784的专栏 7235

java 1e6_java版本 Linux 上报错 EOFException

/data/project/db/ip2region.dbjava.io.EOFExceptionat java.io.RandomAccessFile.readFully(RandomAccessFile.java:438)at org.lionsoul.ip2region.DbSearcher.btreeSearch(DbSearcher.java:292)at org.lionsoul.ip...

weixin_33552230的博客 369

别再傻傻分不清!5分钟搞懂倾斜摄影里‘地面分辨率’和‘模型精度’到底啥关系

本文深入解析倾斜摄影中‘地面分辨率’与‘模型精度’的关系,帮助读者快速理解两者的本质区别与内在关联。通过实战案例和公式计算,详细说明如何从航飞设计到精度验证全流程控制,避免常见认知误区,并针对不同应用场景提供精度需求建议。

weixin_33700350的博客 476

RandomAccessFile readUTF()遇到EOFException的错误

问题: RandomAccessFile file = new RandomAccessFile(filePath, "r"); String str = file.readUTF(); 报错: java.io.EOFException at java.io.RandomAccessFile.readFully(RandomAccessFile.java:438) a

cindy9902的专栏 2840

Python爬虫实战:Playwright 攻克京东图书新书榜(含动态价格与分页)!

我长期专注 Python 爬虫工程化实战,主理专栏 《Python爬虫实战》:从采集策略到反爬对抗,从数据清洗到分布式调度,持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”,让数据价值真正做到——抓得到、洗得净、用得上。

喵手的博客 592

蓝牙协议栈详解(3)——BTstack

BTstack是一个轻量级蓝牙协议栈,支持经典蓝牙(BR/EDR)和低功耗蓝牙(BLE)。它采用事件驱动模型,可运行在MCU/CPU上,通过HCI接口与蓝牙控制器通信。协议栈包含完整的蓝牙协议层支持,如L2CAP、RFCOMM、ATT/GATT等,并提供丰富的示例代码。 主要特点包括模块化设计、开源授权、支持多种HCI传输方式(UART/USB)和操作系统适配。开发时需要关注事件驱动编程模型、内存配置优化、HCI传输稳定性等问题。典型应用场景包括SPP串口通信、BLE外设开发等。 使用建议从最小示例开始,逐

嵌入式软硬件叶玄 291

【JAVA IO】_RandomAccessFile笔记

【JAVA IO】_RandomAccessFile笔记 分类: Java 【JAVA IO】_RandomAccessFile笔记 本章目标: 掌握RandomAccessFile类的作用 可以使用RandomAccessFile读取指定位置的数据 RandomAccessFile类的主要功能是完成随机读取功能,可以读取指定位置的内容。 RandomAc

geili_178的专栏 449

C/C++ LMS算法详解及源码

LMS(Least Mean Squares)算法是一种自适应滤波器算法,用于估计一个系统的参数,以使输出信号与期望信号之间的均方误差最小化。LMS算法通过使用梯度下降的方法,逐步调整自适应滤波器的权值来优化滤波效果。

希望我的博客,能帮上你解决学习中工作中所遇到的问题 3276

java Io RandomAccessFile类 笔记

/** * Io流 * * RandomAccessFile类 随机 随机访问文件 --- 程序可以跳 到文件的任意位置 来读、写文件 。 * @author Administrator * */ public class TestRandomAccessFile { /** * 利用 randomAccessFile类 实现 从文本文件

51互联云 380

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Java IO学习笔记三:MMAP与RandomAccessFile

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用。才能做内存映射),即:把内核的pagecache和文件的数据地址空间映射起来。方法,可以修改文件内容的指针,从而可以方便读取和修改文件中的任意位置。通过mmap生成的且是堆外的和文件映射的内存区域。方法就等同于File中的。

Practitioner 603

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Java IO笔记(3)RandomAccessFile

1.RandomAccessFile RandomAccessFile适用由大小已知的记录组成的文件,所以我们可以使用seek()将记录从一处转移到另一处; RandomAccessFile不是InputStream或者OutputStream继承层次的一部分,是自我独立的类; RandomAccessFile的大部分功能,但不是全部,由nio存储映射文件取代。 2.使用示例 i

Hsienhua's blog 732

Java IO流 学习笔记(三)—— RandomAccessFile

RandomAccessFile 允许来回读写文件,也可以替换文件中的某些部分。 一、创建一个RandomAccessFile 在使用RandomAccessFile之前,必须初始化它, // 第二个参数 “rw”表名你以读写的方式打开文件 RandomAccessFile file = new RandomAccessFile("/opt/file.txt", "rw"); 二、在Rando...

weixin_38536774的博客 300

java io 笔记一:RandomAccessFile(随机访问) 类

欢迎技术交流。 QQ:138986722 跟着计划、今天学习了很多内容、相信忘记的几率很大、所以留下笔记: package iotest; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Date; import bean.Emp; p

胡汉三 2797

JAVA高级视频_IO输入与输出_RandomAccessFile类_笔记

概念:1.RandomAccessFile类 提供了 众多(最多)的 文件 访问 方法;2.RandomAccessFile类 支持 “随机访问” 方式;//不好画图,类似于vector和iterator方式或者数组指针方式。指示器大概就跟迭代器一样吧……3.RandomAccessFlie类 在随机读写 等长记录格式的 文件 时 有优势;//听了这一段的说明觉得指示器就是迭代器……记录格式:内容有规律可循的格式。4.RandomAccessFile类 仅限于 操作文件,不能 访问 其他的 IO设备,如网络

xh3784894的专栏 520

Java IO学习笔记(二):RandomAccessFile类

====================================================== 注:重要!用眼过度需要养眼,点此养眼! ====================================================== 之前的file类只是针对文件本身进行操作的,而如果相对文件内容进行操作,则可以使用randomaccessfile类,此类属于随即读

100

java file和randoM_Java IO系统之File类和RandomAccessFile类学习笔记

File类An abstractrepresentation of file and directory pathnames.User interfacesand operating systems use system-dependentpathname strings to namefiles and directories. This class presents an abstract, ...

weixin_36477752的博客 205

[学习笔记]Java基础_IO(包含对象流序列化使用和RandomAccessFile 类的使用)

概述: •输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。 •输出:将程序(内存)数据输出到磁盘、光盘等存储设备中 •Java 的IO 流主要包括输入、输出两种IO 流,每种输入、输出流有可分为字节流和字符流两大类: –字节流以字节为单位来处理输入、输出操作 –字符流以字符为单位来处理输入、输出操作

Sunny的专栏 808
上一篇: Java IO笔记(BufferedReader/BufferedWriter)
下一篇: java IO笔记(DataInputStream/DataOutputStream)
moonfish0607
博客等级 码龄11年 26粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moonfish0607

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值