JAVA中channel的transferTo方法限制

我们都知道nio中传送数据使用channel+buffer,大的数据可以使用allocateDirect申请直接内存传输以提高效率。

@Test
    public void testNIOFile() {
        long start = System.currentTimeMillis();
        try (FileInputStream is = new FileInputStream("D:\\CCleaner\\CCleaner.exe");
             FileOutputStream os = new FileOutputStream("C:/test.exe");
             FileChannel ic = is.getChannel();
             FileChannel oc = os.getChannel()) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 1024);
            ic.read(buffer);
            buffer.flip();
            oc.write(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("传输完成" + (System.currentTimeMillis() - start));
    }

而NIO包中还提供了更简便的方法,就是channel的transferTo和transferFrom方法

@Test
public void testTransferTo() {
    TimeUtil.start();
    try (FileInputStream fis = new FileInputStream("F:\\test\\x64q.rpf");
         FileOutputStream fos = new FileOutputStream("F:\\x64q.rpf");
         FileChannel isc = fis.getChannel();
         FileChannel osc = fos.getChannel();
    ) {
        isc.transferTo(0,isc.size(),osc);
//            osc.transferFrom(isc,0, isc.size());
    } catch (Exception e) {
        e.printStackTrace();
    }
    TimeUtil.end();
}

而测试大文件时发现TransferTo的对象如果大于2GB的话,只会传送2GB,导致数据丢失,而TransferFrom不会出现这个情况,找资料发现使用while可以传送完,具体原因看这个博客:使用transferTo方法限制文件传输大小的原因分析_狗灬的博客-优快云博客_transferto 大小

<think>嗯,用户让我介绍一下Java中IO和NIO的区别,这是常见的面试题呢。首先我得回忆一下自己学过的知识,确保自己理解正确,然后组织语言让回答清晰有条理。 首先,IO和NIO都是处理输入输出的,但它们的实现方式不同。传统IO是面向流的,而NIO是面向缓冲区的。这一点我记得没错,流是单向的,处理数据的时候需要不断地读取字节,而缓冲区则允许前后移动,处理数据更灵活。不过我得确认一下具体是怎么工作的,比如IO的流分为字节流和字符流,而NIO的Buffer类有不同的子类,比如ByteBuffer。 然后,IO是阻塞的,而NIO是非阻塞的。这里需要解释清楚阻塞和非阻塞的区别。比如,当线程调用read()时,在IO中会一直等到数据读完才能做其他事情,而NIO可以用Selector轮询多个通道,有数据的时候才处理,这样线程不会被阻塞。不过我记得NIO也有阻塞模式,但默认是非阻塞的?这点需要查证,确保正确性。 还有,NIO引入了通道(Channel)的概念,通道可以同时读写,而IO中的流只能单向。比如FileInputStream只能读,FileOutputStream只能写,而FileChannel既可以读也可以写。这也是一个重要的区别点。 另外,NIO的选择器(Selector)允许一个线程处理多个通道,这对高并发场景很有用,而IO每个连接需要单独的线程,资源消耗大。这部分要说明为什么NIO更适合高并发,比如减少线程上下文切换的开销。 可能用户作为面试者,还需要知道实际应用中的选择,比如什么时候用IO,什么时候用NIO。比如传统IO简单易用,适合连接数少的情况,而NIO适合需要处理大量连接但数据量不大的情况,比如聊天服务器。 不过要注意别搞混了NIONIO2。NIO2是在Java7引入的,也就是AIO(异步IO),而NIO本身是非阻塞IO,属于同步非阻塞。这点需要区分清楚,避免在回答中提到AIO导致混淆。 可能用户还会关心性能方面的比较,比如NIO的缓冲区可以减少系统调用的次数,提高效率。同时,零拷贝技术也是NIO的一个优势,比如使用FileChannel.transferTo方法,减少数据在内存中的复制次数,提升传输速度。 另外,异常处理方面,NIO的API可能更复杂一些,因为涉及到缓冲区状态的管理,比如flip()和clear()方法的使用,而传统IO的异常处理相对直接,用try-with-resources就可以自动关闭资源。 总结的时候需要分点列出区别,结构清晰,方便面试时记忆。比如: 1. 流与缓冲:IO是流,单向;NIO是缓冲,双向。 2. 阻塞与非阻塞:IO阻塞,NIO非阻塞。 3. 模型:IO是线程处理连接,NIO是单线程处理多连接。 4. 组件:NIOChannel、Buffer、Selector。 5. 应用场景:IO适合低并发,NIO适合高并发。 最后要加上应用场景的建议,这样回答更全面。还要注意术语的准确性,避免错误,比如不要混淆同步和异步的概念。确保回答中提到的每个点都准确无误,如果有不确定的地方,可能需要查阅资料确认,比如NIO的阻塞模式是否存在,以及Selector的具体工作机制。</think>在Java面试中,对比**IO(传统IO)**和**NIO(New IO)**是一个高频问题。以下是两者的核心区别及其关键点整理: --- ### **1. 基础模型:流(Stream) vs 缓冲(Buffer)** - **传统IO**:基于**流**的模型,数据单向传输(如`InputStream`和`OutputStream`只能读或写),直接操作字节或字符。 - **NIO**:基于**缓冲(Buffer)**和**通道(Channel)**的模型,数据需先读入缓冲区再处理,支持双向读写(如`ByteBuffer`可读写,`FileChannel`可同时操作读写)。 --- ### **2. 阻塞与非阻塞** - **传统IO**:**阻塞式**,线程在读写时会被挂起,直到数据就绪(如`read()`会一直等待数据)。 - **NIO**:**非阻塞式**(核心特性),线程通过轮询`Selector`监听多个`Channel`事件(如数据到达),仅处理就绪的通道,避免线程阻塞。 --- ### **3. 线程模型与性能** - **传统IO**:每个连接需独立线程处理,线程数随连接数线性增长,资源消耗大,适合低并发场景。 - **NIO**:单线程(或少量线程)通过`Selector`管理多个通道,减少线程上下文切换开销,适合高并发、低延迟场景(如聊天服务器)。 --- ### **4. 核心组件** - **传统IO**:`InputStream`、`OutputStream`、`Reader`、`Writer`等。 - **NIO**: - **Buffer**:数据容器(如`ByteBuffer`),支持高效读写操作(需手动`flip()`切换模式)。 - **Channel**:双向数据传输通道(如`FileChannel`、`SocketChannel`)。 - **Selector**:多路复用器,监控多个通道的事件(如连接、读、写)。 --- ### **5. 应用场景** - **传统IO**:适合简单I/O操作、连接数少、数据量大的场景(如文件传输)。 - **NIO**:适合高并发、低延迟的网络应用(如即时通讯、服务器网关),但对编程复杂度要求更高。 --- ### **6. 零拷贝(Zero-Copy)** - **NIO**支持通过`FileChannel.transferTo()`直接在内核态完成文件到网络的传输,减少数据拷贝次数,显著提升性能。 --- ### **代码示例对比** ```java // 传统IO读取文件(阻塞) try (FileInputStream fis = new FileInputStream("file.txt")) { int data; while ((data = fis.read()) != -1) { // 阻塞直到数据就绪 System.out.print((char) data); } } // NIO读取文件(非阻塞) try (FileChannel channel = FileChannel.open(Paths.get("file.txt"))) { ByteBuffer buffer = ByteBuffer.allocate(1024); while (channel.read(buffer) != -1) { buffer.flip(); // 切换为读模式 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } buffer.clear(); // 重置缓冲区 } } ``` --- ### **总结** - **IO**:简单易用,但阻塞模型和高线程开销限制并发能力。 - **NIO**:非阻塞、多路复用、零拷贝等特性,适合高并发场景,但需处理更复杂的API(如缓冲区状态管理)。 在面试中可结合具体场景(如“为何Netty选择NIO”)进一步展开,体现对实际应用的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值