Java回顾总结--RandomAccessFile和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 示例

/**
 * 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使用示例

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

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用RandomAccessFile和MappedByteBuffer来实现Java Socket文件传输。以下是一个简单的示例代码: ```java import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; public class FileTransferServer { public static void main(String[] args) { try { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8080)); System.out.println("等待客户端连接..."); SocketChannel socketChannel = serverSocketChannel.accept(); System.out.println("客户端已连接。"); File file = new File("example.txt"); RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); FileChannel fileChannel = randomAccessFile.getChannel(); long fileSize = file.length(); MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize); socketChannel.write(ByteBuffer.wrap(Long.toString(fileSize).getBytes())); System.out.println("开始传输文件..."); socketChannel.write(mappedByteBuffer); System.out.println("文件传输完成。"); socketChannel.close(); serverSocketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` ```java import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; public class FileTransferClient { public static void main(String[] args) { try { SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("localhost", 8080)); ByteBuffer fileSizeBuffer = ByteBuffer.allocate(8); socketChannel.read(fileSizeBuffer); fileSizeBuffer.flip(); long fileSize = Long.parseLong(new String(fileSizeBuffer.array()).trim()); System.out.println("开始接收文件..."); RandomAccessFile randomAccessFile = new RandomAccessFile("received.txt", "rw"); FileChannel fileChannel = randomAccessFile.getChannel(); MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize); socketChannel.read(mappedByteBuffer); System.out.println("文件接收完成。"); socketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 其中,Server端将文件example.txt传输给Client端,并保存为received.txt。你可以根据需要修改文件名和路径。请确保Server端先运行,然后再运行Client端。这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值