知识详解 IO流

断了今生、忘了曾经 提交于 2020-04-08 11:58:42

IO的介绍

什么是IO?

IO的名称又来是Input与Output的缩写,也就是输入流和输出流。输入流用于从源读取数据,输出流用于向目标写数据。

可以从下列示例图来了解IO流:

 

IO流使用

IO流对文件的操作主要分为字符流和字节流。

字符流

字符流有两个抽象类:WriterReader类。 其对应子类FileWriterFileReader可实现文件的读写操作。 BufferedWriterBufferedReader能够提供缓冲区功能,用以提高效率。

我记得在开始学习Java不久的时候, 在教程中会使用 字符流来进行字符的读取和写入。比较常见的就是,运行一个main方法,然后再控制台输入字符,获取输入的字符做一些逻辑控制之类。 例如: 在控制台输入字符,输入quit退出,输入其它的字符打印。

代码示例:

	public static void main(String[] args)  {
		try {
			test();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void test() throws IOException {
		  String str;
		    // 使用 System.in 创建 BufferedReader 
		    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		    System.out.println("输入字符, 输入 'quit' 退出。");
		    // 读取字符
		    do {
		       str=br.readLine();
		       System.out.println("您输入的字符是:"+str);
		    } while(!str.equals("quit"));
			 br.close();
	}
复制代码

然后我们输入 helloquit结果如下:

输入字符, 输入 'quit' 退出。
hello
您输入的字符是:hello
您输入的字符是:
quit
您输入的字符是:quit
复制代码

通过上述示例我们可以简单的了解下了字符流。 一般来说,我们主要用字符流的情况是读写文件,大部分也是文本文件,比如.txt后缀的。这里我们也顺便介绍下如何使用。

代码示例:

	/**
	 *
	 * 写入和读取文件
	 * @throws IOException
	 */
	private static void test2() throws IOException {
		//创建要操作的文件路径和名称  
        String path ="E:/test/hello.txt";
        String str="hello world";
        FileWriter fw = new FileWriter(path);  
        fw.write(str);  
        fw.close();  
        
        FileReader fr = new FileReader(path);  
        StringBuffer sb=new StringBuffer();
  		while(fr.ready()){
  			sb.append((char)fr.read());
  		}
        System.out.println("输出:"+sb.toString());
        fr.close();
	}

复制代码

注:如果在不同的系统上运行,可以使用 File.separator方法,该方法表示系统的分隔符。

输出结果:

输出:hello word
复制代码

上述代码示例中,我们使用FileWriterFileReader 这两个类对文件进行读写,虽然可以实现字符的写入和读取,但是效率并不高,因为是对磁盘的直接读写。一般对于文件的读写,我们会使用缓冲。使用缓冲的好处就像 倒垃圾一样,将垃圾进行整理堆积,然后到了一定的规模在丢弃,而不是有一点垃圾就倒一次。

那么在上述的代码中加上BufferedWriterBufferedReader类来进行缓冲。

代码示例:

	/**
	 * 写入和读取文件
	 * @throws IOException
	 */
	private static void test3() throws IOException {
		//创建要操作的文件路径和名称  
        String path ="E:/test/hello.txt";
        String str="你好!";
        FileWriter fw = new FileWriter(path);  
        BufferedWriter bw=new BufferedWriter(fw);
        bw.write(str);  
        bw.close();
        fw.close();  
        
        FileReader fr = new FileReader(path);  
        BufferedReader br=new BufferedReader(fr);
        StringBuffer sb=new StringBuffer();
  		while(br.ready()){
  			sb.append((char)br.read());
  		}
        System.out.println("输出:"+sb.toString());
        br.close();
        fr.close();
	}
复制代码

注:需要注意的是关闭的顺序,先关闭缓冲,再关闭文件。

字节流

字节流也有两个抽象类:InputStreamOutputStream类。 其对应子类有FileInputStreamFileOutputStream实现文件读写操作。 BufferedInputStreamBufferedOutputStream提供缓冲区功能

字节流也能对文本进行读取,但是它的主要使用的场景是读取无法直接获取文本信息的二进制文件,比如音乐文件、视频文件、图片文件等等。 这里我们依旧对文件进行读取和写入,不过我们把之前写入到hello.txt文件的内容加上 '你好' 写入到新的文件中。由于这里使用的了中文,所以需要设置相应的编码。

代码示例:

 /**
	 * 创建一个文件并读取记录 
	 * @throws IOException
	 */
	private static void test4() throws IOException {
		String path="E:/test/hello.txt";
		String path2="E:/test/你好.txt";
		String str="你好!";
		//从文件读取数据
		InputStream input = new FileInputStream(path);
		InputStreamReader reader = new InputStreamReader(input, "UTF-8");
	    StringBuffer sb=new StringBuffer();
		while(reader.ready()){
			sb.append((char)reader.read());
		}
		
		input.close();
		reader.close();
		
		//创建一个文件并向文件中写数据
		OutputStream output = new FileOutputStream(path2);
		OutputStreamWriter writer = new OutputStreamWriter(output, "UTF-8");
		writer.write(sb+str);
		
		writer.close();
		output.close();
		
		//从文件读取数据
		InputStream input2 = new FileInputStream(path2);
		InputStreamReader reader2 = new InputStreamReader(input2, "UTF-8");
	    StringBuffer sb2=new StringBuffer();
		while(reader2.ready()){
			sb2.append((char)reader2.read());
		}
		System.out.println("输出:"+sb2);
		input2.close();
		reader2.close();
	}	
复制代码

结果:

	输出:hello world你好!
复制代码

可以看到结果符合我们的预期。

File

学习IO流中,我们也会接触File类。 File类中主要是对文件夹的一些操作。比如,文件夹的创建、删除、查看等等。 这里我们就简单的介绍下File类的相关使用,还是使用代码配合注释来进行说明。

代码示例:

private static void test5() throws IOException {
		String path="E:/test/test2";
		String path2="E:/test/test3/test3";
		String path3="E:/test/test2/test2.txt";
		File f = new File(path);
		File f2 = new File(path2);
		File f3 = new File(path3);
		//创建文件夹
		System.out.println("="+f.mkdir());
		//创建文件夹和所有父文件夹
		System.out.println("=="+f2.mkdirs());
		//创建一个文本
		System.out.println("==="+f3.createNewFile());
		//获取名称
		System.out.println("==="+f3.getName());
		//获取父级名称
		System.out.println("==="+f3.getParent());
		//获取当前路径
		System.out.println("==="+f3.getPath());
		//判断是否是目录
		System.out.println("=="+f2.isDirectory());
		System.out.println("==="+f3.isDirectory());
		//删除该文件
		System.out.println("==="+f3.delete());	
}	
复制代码

输出结果:

=true
==true
===true
===test2.txt
===E:\test\test2
===E:\test\test2\test2.txt
==true
===false
===true
复制代码

关于File类的相关只是简单的介绍了下,具体的使用还需要配置实际的场景。需要注意的是,在进行文件创建和删除的时候,需要先判断是否存在,否则将抛出异常。

 

BIO,NIO,AIO 有什么区别?

简答

  • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。

  • NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。

  • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

详细回答

  • BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

  • NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发

  • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

 

Files的常用方法都有哪些?

  • Files. exists():检测文件路径是否存在。

  • Files. createFile():创建文件。

  • Files. createDirectory():创建文件夹。

  • Files. delete():删除一个文件或目录。

  • Files. copy():复制文件。

  • Files. move():移动文件。

  • Files. size():查看文件个数。

  • Files. read():读取文件。

  • Files. write():写入文件。

 

其它

IO流的基础就介绍到这里了,如果以后有需要的话再进行深入研究吧~如果觉得该文章帮助到你,不妨点个赞,关注公众号一波~

版权声明: 掘金 : https://juejin.im/post/5b25166f51882574957a68b2  掘金

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!