如何在不使用临时文件的情况下在文件的开头添加内容?

    @Test
    public void testRandomAccessFile() throws IOException {
        // 根本没有必要纠结字符集的问题,直接二进制读写就OK
        String fileName = "a.txt";
        String add = "Random";
        byte[] addBytes = add.getBytes();

        RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
        raf.seek(0);

        // 读取 addBytes 长的字节出来
        byte[] tempBytes = new byte[addBytes.length];
        // read 之后会自动移指针,此时 tempBytes 也可能填不满
        int firstLen = raf.read(tempBytes);

        // 将需要添加的字符串添加到文件最前面
        raf.seek(0);
        raf.write(addBytes);

        // 好麻烦,直接就用 addBytes 的长度作为每次读写的长度得了
        byte[] buffer = new byte[tempBytes.length];
        int len;
        int tempLen = 0;
        // 再读取一个数组
        while ((len = raf.read(buffer)) != -1){
            // 如果能读到,就回滚指针
            raf.seek(raf.getFilePointer() - len);
            // 把 tempBytes 里的字节写入
            raf.write(tempBytes);
            // 把 buffer 中的数据转存到 tempBytes
            // 对象复制不能像这样:tempBytes = buffer; 这是把 tempBytes 变量指向了 buffer
            // 不是将 buffer 的数据赋值给 tempBytes
            tempBytes = buffer.clone();
            tempLen = len;
        }
        System.out.println("len = " + len);

        // len == -1 意味着到文件尾了,此时,tempBytes 还有数据没写入
        // 如果 tempLen == 0 ,说明在 while 第一次 raf.read(buffer) 的时候就到末尾了
        if (tempLen == 0){
            // 写入最初的 tempBytes
            raf.write(tempBytes,0,firstLen);
        }
        // 说明是第n次 raf.read(buffer) 才到末尾,此时 tempBytes 可能没有填满
        // tempLen 不可能为 -1
        if (tempLen != 0){
            raf.write(tempBytes,0,tempLen);
        }

        // 释放资源
        raf.close();
    }

之前版本的效率太差了,1G的文件要接近20分钟才能完成添加,我不能接受。

改了一版,每次都读取64k,我用的是固态硬盘,1G的文件用时2秒搞定。

这里假设要添加的内容是小于64k,大于64k情况我懒得搞了。

    @Test
    public void testRandomAccessFile() throws IOException {
        long begin = System.currentTimeMillis();

        // 根本没有必要纠结字符集的问题,直接二进制读写就OK
        String fileName = "E:\\test\\big_file_update.txt";
        String add = "RandomAccessFile\n";
        byte[] addBytes = add.getBytes();
        // 每次读取都是64k 
        int byteLen = 64 * 1024;
        long pointer = 0;
        // 读指针、写指针算起来好麻烦,直接记在变量里面
        long readPointer = 0;
        long writePointer = 0;

        RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
        /// 获取文件原始长度
        long fileLen = raf.length();
        raf.seek(0);

        // 读取 byteLen 长的字节出来
        byte[] tempBytes = new byte[byteLen];
        // read 之后会自动移指针,此时 tempBytes 也可能填不满,文件小于要添加的内容
        int firstLen = raf.read(tempBytes);
        readPointer = raf.getFilePointer();

        // 将需要添加的字符串添加到文件最前面
        raf.seek(0);
        // 写入之后指针在 addBytes.length
        raf.write(addBytes);
        writePointer = raf.getFilePointer();
        // 如果文件长度不大于byteLen,说明第一次读取已经读完了
        if (fileLen <= byteLen){
            // 写入收工
            raf.write(tempBytes,0,firstLen);
            raf.close();
            return;
        }

        // 如果文件长度大于byteLen,说明后面还有,且 tempBytes 是读满的
        // 读指针和写指针是必然要错开的
        // 首先假设要添加的内容是小于byteLen的
        byte[] buffer = new byte[byteLen];
        int len;
        int tempLen = tempBytes.length;

        // 循环读取,写入
        while (true){
            raf.seek(readPointer);
            len = raf.read(buffer);
            readPointer = raf.getFilePointer();
            // 如果readPointer == fileLen,说明文件已读完
            if (readPointer == fileLen){
                // 转到写指针
                raf.seek(writePointer);
                // 把 tempBytes 里的字节写入
                raf.write(tempBytes,0,tempLen);
                raf.write(buffer,0,len);
                // 收工
                break;
            }

            // 转到写指针
            raf.seek(writePointer);
            // 把 tempBytes 里的字节写入
            raf.write(tempBytes,0,tempLen);
            writePointer = raf.getFilePointer();
            if (len == -1){break;}
            // 把 buffer 中的数据转存到 tempBytes
            tempBytes = buffer.clone();
            tempLen = len;
        }

        // 释放资源
        raf.close();

        long end = System.currentTimeMillis();

        System.out.println(end - begin);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值