美文网首页
BIO中RandomAccessFile的使用

BIO中RandomAccessFile的使用

作者: 文景大大 | 来源:发表于2020-04-14 18:33 被阅读0次

    以前我们对文件的读写都使用什么呢?

    如果是字节流,我们有FileInputStream和FileOutputStream;如果是字符流我们有FileReader和FileWriter;

    然而,本文的主角RandomAccessFile可以同时支持对文件的读写,并且可以支持随机访问文件,即访问文件的任意位置内容。如此,我们可以使用多线程的方式来对同一个文件进行读写操作,大大提高了IO的效率。

    首先我们来看一个实例,来熟悉一下RandomAccessFile的使用:

    test.txt

    123456789
    

    Test.java

        public static void main(String[] args) throws IOException {
            // r-只读模式;rw-读写模式
            RandomAccessFile raf = new RandomAccessFile("test.txt","rw");
            log.info("文件中总字节的长度为:{}", raf.length());
            log.info("当前读写指针的位置为:{}", raf.getFilePointer());
    
            // 重置指针到指定位置
            raf.seek(3);
            log.info("当前读写指针的位置为:{}", raf.getFilePointer());
            raf.close();
        }
    

    我们可以通过指定模式来实例化RandomAccessFile对象,这里先只了解最常用的两种模式即可。

    seek的作用在于可以重置读写指针的位置,这是一个非常强大的功能,我们再来看一个例子:

        public static void main(String[] args) throws IOException {
            // r-只读模式;rw-读写模式
            RandomAccessFile raf = new RandomAccessFile("test.txt","rw");
            // 在首部插入hello
            raf.write("hello".getBytes());
            // 重置指针到hello之后
            raf.seek(5);
            raf.writeBytes(",world");
            raf.close();
        }
    

    此时,test.txt中的内容就变为:

    hello,world
    

    我们再来一个多线程复制文件的例子:

    CopyFileThread.java

    @Slf4j
    public class CopyFileThread implements Runnable {
        private RandomAccessFile inFile;
        private RandomAccessFile outFile;
        private Long start;
        private Long end;
        private byte[] readBytes;
        private int readIndex;
    
        public CopyFileThread(String inFile, String outFile, Long start, Long end) throws FileNotFoundException {
            this.start = start;
            this.end = end;
            this.inFile = new RandomAccessFile(inFile, "rw");
            this.outFile = new RandomAccessFile(outFile, "rw");
            // 默认设置一个3字节数组,用来存放每次复制时读取的内容
            this.readBytes = new byte[3];
            // 每次复制时读取的字节数
            this.readIndex = 0;
        }
    
        @Override
        public void run() {
            try {
                // 定位到当前线程分工需要开始读取的地方
                inFile.seek(start);
                // 定位到当前线程分工需要开始写出的地方
                outFile.seek(start);
                // 当前线程分工范围内,且文件未读取完时循环读取
                while(start < end && readIndex != -1){
                    // 防止当前线程越界读取别的线程所负责范围内的字节
                    if((end - start) >= readBytes.length){
                        // 读取readBytes大小的字节
                        this.readIndex = inFile.read(readBytes);
                    } else {
                        // 读取剩余应该读取内容的字节数,此时end-start肯定小于readBytes.length,可以放心地强转
                        this.readIndex = inFile.read(readBytes, 0, (int)(end - start));
                    }
                    // 将读到的数据从头到尾进行写出
                    outFile.write(readBytes, 0, readIndex);
                    start += readIndex;
                }
            } catch (IOException e) {
                log.info("文件复制出现异常:", e);
            } finally {
                try {
                    inFile.close();
                    outFile.close();
                } catch (IOException e) {
                    log.info("随机文件流关闭出现异常:", e);
                }
            }
        }
    }
    

    Test.java

    @Slf4j
    public class Test {
        private static final String IN_FILE = "test1.txt";
        private static final String OUT_FILE = "test2.txt";
        private static final Integer THREAD_COUNT = 2;
    
        public static void main(String[] args) throws IOException {
            startCopyFile(IN_FILE, OUT_FILE, THREAD_COUNT);
        }
    
        private static void startCopyFile(String inFile, String outFile, int threadCount) throws FileNotFoundException {
            // 每个线程需要负责拷贝的字节长度
            long segmentFileLength = new File(IN_FILE).length() / threadCount;
            for (int i = 0; i < threadCount; i++) {
                // 为每个线程进行分工
                new Thread(new CopyFileThread(IN_FILE, OUT_FILE, i*segmentFileLength, (i+1)*segmentFileLength)).start();
            }
        }
    }
    

    关于多线程如何调试,可以参考这篇文章《IDEA调试技巧进阶》

    相关文章

      网友评论

          本文标题:BIO中RandomAccessFile的使用

          本文链接:https://www.haomeiwen.com/subject/jywgmhtx.html