Java回顾总结--RandomAccessFile和NIO

目录

  • 一、RandomAccessFile
      • [1.1 为什么要有RandomAccessFile?](#1.1 为什么要有RandomAccessFile?)
      • [1.2 常用方法简介](#1.2 常用方法简介)
      • [1.3 RandomAccessFile 特点和优势](#1.3 RandomAccessFile 特点和优势)
        • [1.3.1 既可以读也可以写](#1.3.1 既可以读也可以写)
        • [1.3.2 可以指定位置读写](#1.3.2 可以指定位置读写)
      • [1.4 示例](#1.4 示例)
  • 二、NIO

一、RandomAccessFile

1.1 为什么要有RandomAccessFile?

RandomAccessFile 类在 Java 中的作用主要是允许我们以随机访问的方式读取和写入文件内容。这与传统的顺序访问文件不同,传统方式是从文件的开头开始逐个字节或一定大小的数据块依次读取或写入。

我们可能会使用 RandomAccessFile:

  • 随机读取和写入文件内容:RandomAccessFile 允许我们通过指定文件中的位置(偏移量)来直接读取或写入数据,而不需要按照顺序逐个字节地读取或写入。这对于需要随机访问文件内容的应用程序非常有用。
  • 修改文件内容:通过 RandomAccessFile,我们可以定位到文件中的特定位置,并修改该位置的内容,而不会影响到其他部分的数据。
  • 读取和写入大文件:当处理大文件时,RandomAccessFile 可以更高效地处理文件的读取和写入操作,因为可以直接跳转到文件中的指定位置。
  • 实现文件锁定:RandomAccessFile 还提供了一些方法来实现文件的锁定,以确保在多线程环境下对文件的安全访问。

也可以使用RandomAccessFile 实现多线程分段下载的功能。

1.2 常用方法简介

  • 构造方法: RandomAccessFile raf = newRandomAccessFile(File file, String mode);

    其中参数 mode 的值可选 "r": 可读, "w" : 可写, "rw": 可读写;

  • 成员方法:

    seek(int index);可以将指针移动到某个位置开始读写;

    ​setLength(long len);给写入文件预留空间:

1.3 RandomAccessFile 特点和优势

1.3.1 既可以读也可以写

RandomAccessFile不属于InputStream和OutputStream类系的它是一个完全独立的类, 所有方法(绝大多数都只属于它自己)都是自己从头开始规定的,这里面包含读写两种操作。

1.3.2 可以指定位置读写

RandomAccessFile能在文件里面前后移动, 在文件里移动用的seek( ),所以它的行为与其它的I/O类有些根本性的不同。 总而言之, 它是一个直接继承Object的, 独立的类。 只有RandomAccessFile才有seek搜寻方法, 而这个方法也只适用于文件。

1.4 示例

java 复制代码
/**
 * RandomAccessFile的使用
 * 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
 * 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
 *
 * 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
 *   如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
 * 4. 可以通过相关的操作,实现RandomAccessFile"插入"数据的效果
 */
public class RandomAccessFileTest {

    @Test
    public void test1() {

        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            //1.
            raf1 = new RandomAccessFile(new File("爱情与友情.jpg"),"r");
            raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"),"rw");
            //2.
            byte[] buffer = new byte[1024];
            int len;
            while((len = raf1.read(buffer)) != -1){
                raf2.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.
            if(raf1 != null){
                try {
                    raf1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            if(raf2 != null){
                try {
                    raf2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    @Test
    public void test2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        raf1.write("xyz".getBytes());//

        raf1.close();

    }
    /*
    使用RandomAccessFile实现数据的插入效果
     */
    @Test
    public void test3() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len)) ;
        }
        //调回指针,写入"xyz"
        raf1.seek(3);
        raf1.write("xyz".getBytes());

        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());

        raf1.close();

        //思考:将StringBuilder替换为ByteArrayOutputStream
    }
}

二、NIO

NIO------FileChannel

Channel是对I/O操作的封装。

FileChannel配合着ByteBuffer, 将读写的数据缓存到内存中, 然后以批量/缓存的方式read/write, 省去了非批量操作时的重复中间操作, 操纵大文件时可以显著提高效率( 和Stream以byte数组方式有什么区别? 经过测试, 效率上几乎无区别) 。

NIO使用示例

java 复制代码
public class FileChannelDemo {

    public static void main(String[] args) {
        try {
            // 创建一个 RandomAccessFile 对象,以读写模式打开文件
            RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
            FileChannel channel = file.getChannel(); // 获取文件的 FileChannel

            // 写入数据到文件
            String data = "Hello, FileChannel!";
            ByteBuffer buffer = ByteBuffer.allocate(1024); // 创建一个 ByteBuffer
            buffer.put(data.getBytes()); // 将数据写入 ByteBuffer
            buffer.flip(); // 切换为读模式
            channel.write(buffer); // 将数据写入 FileChannel

            // 重置文件指针位置到开头
            channel.position(0);

            // 读取文件数据
            buffer.clear(); // 清空 ByteBuffer
            int bytesRead = channel.read(buffer); // 从 FileChannel 读取数据到 ByteBuffer

            if (bytesRead > 0) {
                buffer.flip(); // 切换为读模式
                byte[] readData = new byte[bytesRead];
                buffer.get(readData); // 从 ByteBuffer 中读取数据
                System.out.println("Read data from file: " + new String(readData));
            } else {
                System.out.println("No data read from file.");
            }

            // 关闭 FileChannel 和 RandomAccessFile
            channel.close();
            file.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

参考链接:

【NIO实战】深入理解FileChannel
Java NIO

相关推荐
Themberfue12 分钟前
基础算法之双指针--Java实现(下)--LeetCode题解:有效三角形的个数-查找总价格为目标值的两个商品-三数之和-四数之和
java·开发语言·学习·算法·leetcode·双指针
深山夕照深秋雨mo21 分钟前
在Java中操作Redis
java·开发语言·redis
努力的布布26 分钟前
SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器
java·后端·spring
xujinwei_gingko27 分钟前
Spring MVC 常用注解
java·spring·mvc
PacosonSWJTU31 分钟前
spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)
java·后端·springmvc
PacosonSWJTU33 分钟前
spring揭秘26-springmvc06-springmvc注解驱动的web应用
java·spring·springmvc
原野心存1 小时前
java基础进阶——继承、多态、异常捕获(2)
java·java基础知识·java代码审计
进阶的架构师1 小时前
互联网Java工程师面试题及答案整理(2024年最新版)
java·开发语言
黄俊懿1 小时前
【深入理解SpringCloud微服务】手写实现各种限流算法——固定时间窗、滑动时间窗、令牌桶算法、漏桶算法
java·后端·算法·spring cloud·微服务·架构
木子02041 小时前
java高并发场景RabbitMQ的使用
java·开发语言