GVKun编程网logo

Java IO(javaio流)

11

想了解JavaIO的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于javaio流的相关问题,此外,我们还将为您介绍关于旧IO(java.io.*)和新IO(java.nio.*)的主要区别、

想了解Java IO的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于javaio流的相关问题,此外,我们还将为您介绍关于 旧IO(java.io.*)和新IO(java.nio.*)的主要区别、corejava Java NIO:IO与NIO的区别、fastdfs文件上传报错Save file error:java.io.IOException: java.io.IOException: java.io.IOException: recv package size -1 != 10、Java 9,Hibernate和java.sql / javax.transaction的新知识。

本文目录一览:

Java IO(javaio流)

Java IO(javaio流)

Java IO

概述

Java的I/O大概可以分成以下几类:

  • 磁盘操作:File
  • 字节操作:InputStream和OutputStream
  • 字符操作:Reader和Writer
  • 对象操作:Serializable
  • 网路操作:Socket
  • 新的输入/输出:NIO

 

1、流的概念和作用

流:代表任何有能力产出数据的数据源对象或者使有能力接受数据的接收对象

流的本质:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

流的作用:为数据源和目的建立一个输送通道。

 

Java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。

 

Java IO所采用的模型

Java的IO模型设计非常优秀,它使用decorator(装饰者)模式,按功能划分Stream,可以动态装配这些Stream,以获得需要的功能。

字节流和字符流

字节流读取的时候,读到一个字节就返回一个字节;字符流使用字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)。先去查指定的编码表,将查到的字符返回。字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流智能处理字符数据。只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。字节流主要操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream。字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的。

 

NIO

NIO的特性/NIO与IO区别

Java NIOjava 1.4 之后新出的一套IO接口,这里的的新是相对于原有标准的Java IO和Java Networking接口。NIO提供了一种完全不同的操作方式。

NIO中的N可以理解为Non-blocking,不单纯是New。

NIO的特性/NIO与IO区别

1 Channels and Buffers(通道和缓冲区)

IO是面向流的,NIO是面向缓冲区的

  • 标准的IO编程接口是面向字节流和字符流的。而NIO是面向通道和缓冲区的,数据总是从通道中读到buffer缓冲区内,或者从buffer缓冲区写入到通道中;( NIO中的所有I/O操作都是通过一个通道开始的。)
  • Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方;
  • Java NIO是面向缓存的I/O方法。 将数据读入缓冲器,使用通道进一步处理数据。 在NIO中,使用通道和缓冲区来处理I/O操作。

2 Non-blocking IO(非阻塞IO)

IO流是阻塞的,NIO流是不阻塞的

  • Java NIO使我们可以进行非阻塞IO操作。比如说,单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
  • Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了

3 Selectors(选择器)

NIO有选择器,而IO没有。

  • 选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。
  • 线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。

读数据和写数据方式

通常来说NIO中的所有IO都是从 Channel(通道) 开始的。

从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。

从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。

数据读取和写入操作图示:

NIO核心组件简单介绍

NIO包含下面几个核心的组件

  • Channels
  • Buffers
  • Selectors

整个NIO体系包含的类远远不止这三个,只能说这三个是NIO体系的"核心API"

通道

在Java NIO中,主要使用的通道如下(涵盖了UDP和TCP网络IO,以及文件IO)

  • DatagramChannel
  • SocketChannel
  • FileChannel
  • ServerSocketChannel

缓冲区

在Java NIO中使用的核心缓冲区如下(覆盖了通过I/O发送的基本数据类型:byte、char、short、int、long、float、double、long)

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • InBuffer
  • FloatBuffer
  • DoubleBuffer
  • LongBuffer

选择器

Java NIO提供了"选择器"的概念。这是一个可以用于监听多个通道的对象,如数据达到,连接打开等。因此,单线程可以见识多个通道中的数据。

如果应用程序有多个通道(连接)打开,但每隔连接的流量都很低,则可考虑使用它。例如在聊天服务器中下面是一个单线程中Slector维护3个Channel的示意图:

要使用Selector的话,我们必须把Channel注册到Selector上,然后就可以调用Selector的select()方法。这个方法会进入阻塞,直到有一个channel的状态符合条件。当方法返回后,线程可以处理这些事件。

NIO快速复制文件的实例:

 旧IO(java.io.*)和新IO(java.nio.*)的主要区别

旧IO(java.io.*)和新IO(java.nio.*)的主要区别

 旧IO(java.io.*)和新IO(java.nio.*)的主要区别,如下表:

IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
选择器

java.nio.*是JDK1.4加入的。

下面分别介绍:

一、面向流与面向缓冲

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

        Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

二、阻塞与非阻塞

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

        Java NIO的非阻塞模式,如使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。一个单独的线程可以管理多个输入和输出通道(channel)。

三、选择器(Selectors)

        Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

概念参考地址:http://ifeve.com/java-nio-vs-io/

四、性能比较(冰山一角)

在此,就拿最简单的文件操作为例,从一个文件读数据并写入另一个文件,简而言之就是copy。代码如下:

public class IOAndNIO {
	private static final String sourcePath = "C:/Users/Administrator/Desktop/123.txt";
	private static final String destPath = "test-nio.txt";

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			long atime = System.currentTimeMillis();
			//nio方式
			runWithNIO();
			long btime = System.currentTimeMillis();
			System.out.println("nio-time:"+(btime-atime));
			
			atime = System.currentTimeMillis();
			//传统方式
			runWithIO();
			btime = System.currentTimeMillis();
			System.out.println("io-time:"+(btime-atime));
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	@SuppressWarnings("resource")
	public static void runWithNIO() throws IOException {
		final int BSIZE = 1024;
		FileChannel in = new FileInputStream(sourcePath).getChannel();
		FileChannel out = new FileOutputStream(destPath).getChannel();
		ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
		while (in.read(buffer) != -1) {
			buffer.flip(); // Prepare for writing
			out.write(buffer);
			buffer.clear(); // Prepare for reading
		}
	}

	public static void runWithIO() throws IOException {
		String file = "test-io.txt";
		BufferedReader in = new BufferedReader(new StringReader(read()));
		PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
		String s = "";
		while ((s = in.readLine()) != null)
			out.println(s);
		out.close();
	}
	// 读文件
	public static String read() throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(sourcePath));
		String str;
		StringBuilder sb = new StringBuilder();
		while ((str = in.readLine()) != null)
			sb.append(str + "\n");
		in.close();
		return sb.toString();
	}
}

在文件很小的时候看不出区别,所以将测试文件大小增加到2M,测试结果如下:

很明显nio采用的缓冲器,大大提升了速度。

在上述代码nio段中,调用了read()方法后,数据就会输入到缓冲器,所以就必须调用缓冲器的flip()方法,告诉缓冲器即将会有读取字节的操作,write()方法操作后,数据仍在缓冲器中,所以必须要调用clear()方法,对所有内部指针重新安排以便下一次read(),缓冲器接受数据。

除此方法外,还有一个更简单的方法,即调用transferTo()函数,该函数允许一个通道(channel)和另一个通道直接相连。

将runWithNIO()方法改为如下:

public static void runWithNIO() throws IOException {
		FileChannel in = new FileInputStream(sourcePath).getChannel();
		FileChannel out = new FileOutputStream(destPath).getChannel();
		in.transferTo(0, in.size(), out);
	}

 

除了以上区别,nio包下还提供了例如Charset类,提供字符的编码与解码,方便实用。

 

暂时总结到这,再补充。若有错误,望纠正。

corejava Java NIO:IO与NIO的区别

corejava Java NIO:IO与NIO的区别

一、概念

     NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。

二、NIO和IO的主要区别

下表总结了Java IO和NIO之间的主要区别:

IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
选择器

 

 

 

 

1、面向流与面向缓冲

     Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

2、阻塞与非阻塞IO

     Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

3、选择器(Selectors)

     Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

三、NIO和IO如何影响应用程序的设计

无论您选择IO或NIO工具箱,可能会影响您应用程序设计的以下几个方面:

1.对NIO或IO类的API调用。
2.数据处理。
3.用来处理数据的线程数。

1、API调用

当然,使用NIO的API调用时看起来与使用IO时有所不同,但这并不意外,因为并不是仅从一个InputStream逐字节读取,而是数据必须先读入缓冲区再处理。

2、数据处理

使用纯粹的NIO设计相较IO设计,数据处理也受到影响。

在IO设计中,我们从InputStream或 Reader逐字节读取数据。假设你正在处理一基于行的文本数据流,例如:

Name: Anna 
Age: 25
Email: anna@mailserver.com 
Phone: 1234567890

该文本行的流可以这样处理:

复制代码

InputStream input = ... ; // get the InputStream from the client socket   

BufferedReader reader = new BufferedReader(new InputStreamReader(input));   

String nameLine   = reader.readLine(); 
String ageLine    = reader.readLine(); 
String emailLine  = reader.readLine(); 
String phoneLine  = reader.readLine();

复制代码

     请注意处理状态由程序执行多久决定。换句话说,一旦reader.readLine()方法返回,你就知道肯定文本行就已读完, readline()阻塞直到整行读完,这就是原因。你也知道此行包含名称;同样,第二个readline()调用返回的时候,你知道这行包含年龄等。 正如你可以看到,该处理程序仅在有新数据读入时运行,并知道每步的数据是什么。一旦正在运行的线程已处理过读入的某些数据,该线程不会再回退数据(大多如此)。下图也说明了这条原则:

而一个NIO的实现会有所不同,下面是一个简单的例子:

ByteBuffer buffer = ByteBuffer.allocate(48); 
int bytesRead = inChannel.read(buffer);

注意第二行,从通道读取字节到ByteBuffer。当这个方法调用返回时,你不知道你所需的所有数据是否在缓冲区内。你所知道的是,该缓冲区包含一些字节,这使得处理有点困难。假设第一次 read(buffer)调用后,读入缓冲区的数据只有半行,例如,“Name:An”,你能处理数据吗?显然不能,需要等待,直到整行数据读入缓存,在此之前,对数据的任何处理毫无意义。所以,你怎么知道是否该缓冲区包含足够的数据可以处理呢?好了,你不知道。发现的方法只能查看缓冲区中的数据。其结果是,在你知道所有数据都在缓冲区里之前,你必须检查几次缓冲区的数据。这不仅效率低下,而且可以使程序设计方案杂乱不堪。例如:

复制代码

ByteBuffer buffer = ByteBuffer.allocate(48);   

int bytesRead = inChannel.read(buffer);   

while(! bufferFull(bytesRead) ) {   
       bytesRead = inChannel.read(buffer);   
}

复制代码

bufferFull()方法必须跟踪有多少数据读入缓冲区,并返回真或假,这取决于缓冲区是否已满。换句话说,如果缓冲区准备好被处理,那么表示缓冲区满了。

bufferFull()方法扫描缓冲区,但必须保持在bufferFull()方法被调用之前状态相同。如果没有,下一个读入缓冲区的数据可能无法读到正确的位置。这是不可能的,但却是需要注意的又一问题。

如果缓冲区已满,它可以被处理。如果它不满,并且在你的实际案例中有意义,你或许能处理其中的部分数据。但是许多情况下并非如此。下图展示了“缓冲区数据循环就绪”:

四、总结

NIO可让您只使用一个(或几个)单线程管理多个通道(网络连接或文件),但付出的代价是解析数据可能会比从一个阻塞流中读取数据更复杂。

如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,实现NIO的服务器可能是一个优势。同样,如果你需要维持许多打开的连接到其他计算机上,如P2P网络中,使用一个单独的线程来管理你所有出站连接,可能是一个优势。一个线程多个连接的设计方案如下图所示:

Java NIO: 单线程管理多个连接

如果你有少量的连接使用非常高的带宽,一次发送大量的数据,也许典型的IO服务器实现可能非常契合。下图说明了一个典型的IO服务器设计:

Java IO: 一个典型的IO服务器设计- 一个连接通过一个线程处理.

fastdfs文件上传报错Save file error:java.io.IOException: java.io.IOException: java.io.IOException: recv package size -1 != 10

fastdfs文件上传报错Save file error:java.io.IOException: java.io.IOException: java.io.IOException: recv package size -1 != 10

这是什么原因?文件好像也能上传

Java 9,Hibernate和java.sql / javax.transaction

Java 9,Hibernate和java.sql / javax.transaction

我试图使用Hibernate将项目“升级”到Java 9,但是我在使模块正常运行时遇到了问题.

我的module-info.java的相关部分如下所示:

module test {

    ...

    requires java.base;
    requires hibernate.core;
    requires javax.transaction;
    requires java.sql;

}

以及我POM中的相关依赖项

> org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec,2.0.0.Alpha1
> org.hibernate:hibernate-core,5.2.12.Final
> javax.transaction:javax.transaction-api,1.2

问题是,如果我运行程序,我得到javax.transaction.SystemException的NoClassDefFoundError.我调查了这个,很明显,my module is missing a requires on javax.transaction.

所以我在javax.transaction-api上添加了一个模块依赖.然后我继续尝试再次运行程序 – 现在我缺少java.sql.sqlException.

这是我遇到的问题:如果我add a dependency on the module java.sql,包含这个类,我最终会发生冲突:

module reads package javax.transaction.xa from both java.sql and javax.transaction.api

java.sql和javax.transaction.api包含不同的包,并且有一个共同的(javax.transaction.xa),但我需要所有这些包.

我该如何处理?我有什么简单的遗失吗?

最佳答案
使用版本1.3而不是javax.transaction-api的1.2,在此版本中已删除javax.transaction.xa.

Maven依赖:

今天关于Java IOjavaio流的分享就到这里,希望大家有所收获,若想了解更多关于 旧IO(java.io.*)和新IO(java.nio.*)的主要区别、corejava Java NIO:IO与NIO的区别、fastdfs文件上传报错Save file error:java.io.IOException: java.io.IOException: java.io.IOException: recv package size -1 != 10、Java 9,Hibernate和java.sql / javax.transaction等相关知识,可以在本站进行查询。

本文标签: