×

nio写入文件速度

nio写入文件速度(写入速度和下载速度)

admin admin 发表于2023-04-02 11:20:10 浏览52 评论0

抢沙发发表评论

本文目录一览:

java nio bytebuffer文件读写问题

JDK1.4以后就提供java.nio的包,nio主要提供字节与字符的映射、内存映射文件和文件加锁机制

其中内存映射文件在读取大文件时可能会用上,因为内存映射不是直接把文件加载到JVM内存空间

而是借用操作系统对文件的读取,这经历了由当前Java态进入到操作系统内核态,再由操作系统读取文件,

并返回数据到当前Java态的过程。由Java态进入操作系统内核态离不开nio包中两个重要的类

FileChannel 和 ByteBuffer。FileChannel表示文件通道,可以从FileInputStream、FileOutputStream

以及RandomAccessFile对象获取文件通道,你可以从文件通道直接读取文件,也可以使用“内存映射”

即使用通道,将文件内存映射到ByteBuffer,可以映射一部分内容,也可以映射全部内容,使用内存映射

能大幅提高我们操作大文件的速度

FileChannel 和 ByteBuffer文件读取

[java] view plain copy

package nio;

import java.io.BufferedInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.nio.ByteBuffer;

import java.nio.MappedByteBuffer;

import java.nio.channels.FileChannel;

import java.nio.channels.FileChannel.MapMode;

/**

*

* Channel类似与流,数据可以从Channel读取到Buffer,也可以从Buffer写入到Channel

* 但通道和流还是有区别,比如流只能是单向读或写,而通道可以异步读写

*

* @author yli

*/

public class FileChannelTest {

真正理解NIO

一个使用传统阻塞I/O的系统,如果还是使用传统的一个请求对应一个线程这种模式,一旦有高并发的大量请求,就会有如下问题: 

1、线程不够用, 就算使用了线程池复用线程也无济于事; 

2、阻塞I/O模式下,会有大量的线程被阻塞,一直在等待数据,这个时候的线程被挂起,只能干等,CPU利用率很低,换句话说,系统的吞吐量差; 

3、如果网络I/O堵塞或者有网络抖动或者网络故障等,线程的阻塞时间可能很长。整个系统也变的不可靠;

java.nio全称java non-blocking IO(实际上是 new io),是指JDK 1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供 缓存 支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。-nio写入文件速度

HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。

原有的 IO 是面向流的、阻塞的,NIO 则是面向块的、非阻塞的。

java1.4以前的io模型,一连接对一个线程。

原始的IO是面向流的,不存在缓存的概念。Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区-nio写入文件速度

Java IO的各种流是阻塞的,这意味着当一个线程调用read或 write方法时,该线程被阻塞,直到有一些数据被读取,或数据完全写入,该线程在此期间不能再干任何事情了。

NIO是面向缓冲区的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性。

Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。-nio写入文件速度

通俗理解:NIO是可以做到用一个线程来处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或者100个线程来处理。不像之前的阻塞IO那样,非得分配10000个。

在标准IO API中,你可以操作字节流和字符流,但在新IO中,你可以操作通道和缓冲,数据总是从通道被读取到缓冲中或者从缓冲写入到通道中。

NIO核心API Channel, Buffer, Selector

NIO的通道类似于流,但有些区别如下:

1. 通道可以同时进行读写,而流只能读或者只能写

2. 通道可以实现异步读写数据

3. 通道可以从缓冲读数据,也可以写数据到缓冲: 

缓冲区本质上是一个可以写入数据的内存块,然后可以再次读取,该对象提供了一组方法,可以更轻松地使用内存块,使用缓冲区读取和写入数据通常遵循以下四个步骤:

1. 写数据到缓冲区;

2. 调用buffer.flip()方法;

3. 从缓冲区中读取数据;

4. 调用buffer.clear()或buffer.compat()方法;

当向buffer写入数据时,buffer会记录下写了多少数据,一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式,在读模式下可以读取之前写入到buffer的所有数据,一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。-nio写入文件速度

Buffer在与Channel交互时,需要一些标志:

buffer的大小/容量 -  Capacity

作为一个内存块,Buffer有一个固定的大小值,用参数capacity表示。

当前读/写的位置 -  Position

当写数据到缓冲时,position表示当前待写入的位置,position最大可为capacity – 1;当从缓冲读取数据时,position表示从当前位置读取。

信息末尾的位置 -  limit

在写模式下,缓冲区的limit表示你最多能往Buffer里写多少数据; 写模式下,limit等于Buffer的capacity,意味着你还能从缓冲区获取多少数据。

下图展示了buffer中三个关键属性capacity,position以及limit在读写模式中的说明:

缓冲区常用的操作

向缓冲区写数据:

    1. 从Channel写到Buffer;

    2. 通过Buffer的put方法写到Buffer中;

从缓冲区读取数据:

    1. 从Buffer中读取数据到Channel;

    2. 通过Buffer的get方法从Buffer中读取数据;

flip方法:

     将Buffer从写模式切换到读模式,将position值重置为0,limit的值设置为之前position的值;

clear方法 vs compact方法:

       clear方法清空缓冲区;compact方法只会清空已读取的数据,而还未读取的数据继续保存在Buffer中;

一个组件,可以检测多个NIO channel,看看读或者写事件是否就绪。

多个Channel以事件的方式可以注册到同一个Selector,从而达到用一个线程处理多个请求成为可能。

Thanks for:

学习NIO

美团wiki-NIO

NIO的使用介绍

BIO是基于字节流和字符流进行操作的,而NIO是基于通道和缓冲区进行操作的,数据总是从通道中读取到缓冲区,或者从缓冲区写入到通道中。

BIO是阻塞式的,而NIO是非阻塞式的,读写的效率要更加地高。

Channel有点类似BIO中的流的概念,但是比流要强大地多,主要体现在以下方面:

Channel有以下几个基本类型:

关于Channel的使用,给出如下一个简单的示例,将test1中的内容使用channel和buffer拷贝到test2文件中:

除此之外,我们还可以直接将数据从一个channer传输到另外一个channel中。

buffer本质上是一块可以读写数据的缓存,一般遵循以下的使用步骤:

在buffer中有如下几个重要的属性需要掌握:

Buffer基本类型:

这些类型基本上涵盖了你能通过IO发送的数据类型。

channel和buffer之间的读写关系并不是严格的一对一关系,可以通过scatter方式将一个channel中的数据写入多个buffer之中,也可以通过gather方式将多个buffer中的数据读取到一个channel中。-nio写入文件速度

一个Selector线程能注册多个Channel,并对它们进行(非)阻塞式地监听,任意一个Channel有事件就绪,Selector就将该事件交给对应的业务线程进行处理,Selector继续对注册的Channel进行监听。-nio写入文件速度

我们这里以服务端的一个实现来介绍Selector多路复用器的使用:

在实际的开发实践中,很少有人直接使用NIO,因为它使用起来比较复杂,而且在linux上还存在Bug,比如epoll的空轮询导致CPU100%的问题;而且重复造轮子会导致开发效率底下,无法保证程序的质量,所以大家都倾向于使用基于NIO实现的中间件工具,比如Netty。-nio写入文件速度

io和nio的文件读取方式的不同

io,也称old io,读取文件主要通过流,从磁盘上一个一个字符的读,效率比较低下。

nio,在对文件操作下改进了方式,通过块读取,一整块一整块的读取,所以读取出来的不会是一个字符,而是一个块,把这些数据放到内存缓冲区内。在进行操作。通过块的读取来提高速度。(块操作,fileChannel)-nio写入文件速度

内存映射,MappedByteBuffer,这个主要是通过内存映射,即利用虚拟内存(把文件某一部分当成内存),直接操作文件,对于一些要在内存中大块操作的文件,比如1G的文件

你要在内存中操作200M的部分,,把200M读到物理内存是比较耗内存和CPU的,不如直接把那部分文件虚拟成内存直接操作。

下面是对用以上三个文式对一个300M的文件进行读取,并写入另一个文件的测试:

1. inputstream CPU5.6% 内存2.6M costTime:4.039S 使用缓冲区byte:4kb-nio写入文件速度

2. filechannel CPU1.3% 内存2.6M costTime:3.359S 使用缓冲区byte:0(transferTo方式)-nio写入文件速度

3. MappedByteBuffer CPU6.9% 内存2.4M costTime:6.966S 内存映射:300M

可见对大文件块读取是最好的;如果要直接操作文件的很大的一部分的内容,则比较适合MappedByteBuffer ;如读取很小的内容,比如8B的内容,inputStream可能是最好的。

代码如下,选几个文件自已试下。使用jdk自带JConsole进行观察。

public class Test {

public static void main(String[] args)throws Exception{

File ff=new File("F:/workspace/pureMQ/src/mq/pure/file/cc.rar");

File[] f=new File[7];

File[] f_write=new File[7];

Thread.sleep(15000);

for(int i=0;i7;i++){

f[i]=new File("F:/workspace/pureMQ/src/mq/pure/file/1"+(i+1)+".jpg");

}

for(int i=0;i7;i++){

f_write[i]=new File("F:/workspace/pureMQ/src/mq/pure/file/"+i+".jpg");

if(!f_write[i].exists()){

f_write[i].createNewFile();

}

}

f[0]=ff;

long begin=System.currentTimeMillis();

int choice=1;

for(int i=0;i7;i++){

switch(choice){

case 1:

System.out.println("1");

InputStream ips=new FileInputStream(f[i]);

OutputStream ops=new FileOutputStream(f_write[i]);

byte[] b=new byte[4096];

int index;

while((index=ips.read(b))!=-1){

ops.write(b);

}

if(ips!=null){

ips.close();

}

if(ops!=null){

ops.close();

}

break;

case 2:

System.out.println("2");

RandomAccessFile raf=new RandomAccessFile(f[i],"r");

RandomAccessFile raf_write=new RandomAccessFile(f_write[i],"rw");

FileChannel fc=raf.getChannel();

FileChannel fc_write=raf_write.getChannel();

fc.transferTo(0, fc.size(), fc_write);

fc.close();

fc_write.close();

raf.close();

raf_write.close();

break;

case 3:

System.out.println("3");

RandomAccessFile raf2=new RandomAccessFile(f[i],"r");

RandomAccessFile raf2_write=new RandomAccessFile(f_write[i],"rwd");

FileChannel fc2=raf2.getChannel();

FileChannel fc2_write=raf2_write.getChannel();

MappedByteBuffer mbb=fc2_write.map(MapMode.READ_WRITE, 0, fc2.size());

ByteBuffer bb=ByteBuffer.allocate(4096);

while(fc2.read(bb)!=-1){

bb.flip();

mbb.put(bb);

bb.compact();

}

mbb.force();

fc2.close();

fc2_write.close();

raf2.close();

raf2_write.close();

break;

default:

break;

}

}

long end=System.currentTimeMillis();

System.out.println("all time cost:"+ (end-begin));

}

}

Java中nio与普通io有什么优势?

1,nio的主要作用就是用来解决速度差异的。举个例子:计算机处理的速度,和用户按键盘的速度,这两者的速度相差悬殊。

2,如果按照经典的方法:一个用户设定一个线程,专门等待用户的输入,无形中就造成了严重的资源浪费,每一个线程都需要珍贵的cpu时间片,由于速度差异造成了在这个交互线程中的cpu都用来等待。

3,传统的阻塞式IO,每个连接必须要开一个线程来处理,并且没处理完线程不能退出。

4,非阻塞式IO,由于基于反应器模式,用于事件多路分离和分派的体系结构模式,所以可以利用线程池来处理。事件来了就处理,处理完了就把线程归还。

5,而传统阻塞方式不能使用线程池来处理,假设当前有10000个连接,非阻塞方式可能用1000个线程的线程池就搞定了,而传统阻塞方式就需要开10000个来处理。如果连接数较多将会出现资源不足的情况。非阻塞的核心优势就在这里。-nio写入文件速度

java如何合并多个大的txt文件?(每个文件50M)。nio处理文件如何提高速度?

这种情况java.io, nio没有大区别

byte[] buf = new byte[8 * 1024];

try (OutputStream out = new new FileOutputStream(outfile)) {

    for (File f : txtFiles) {

        try (FileInputStream in = new FileInputStream(f)) {

           org.apache.commons.io.IOUtils.copyLarge(in, out, buf);

        }

    }

}

要是linux下,shell里直接执行cat *.txt out.txt就可以,不用写代码