浅谈IO和NIO

    首先我们需要明确一点,那就是JAVA中我们常说的输入输出都是相对于内存来说的,写入内存就是我们常说的输入流,写出内存就是我们说的输出流.只有明确了这个概念我们说的输入流和输出流才是有意义的.

    下面我们通过一张图来认识一下我们的输入流和输出流:




    看了上面的图片,相信我们会对IO的分类有一个详细的认识:字节流和字符流,输入流还是有输出流.下面我们通过一些demo来认识一下这个流的使用吧

//演示InputStream(字节输入流)
	public static void inputStreamTest() {
		InputStream inputStream = null;
		
		try {
			inputStream = new FileInputStream("F://test/inputStream.txt");
			byte bt[] = new byte[1024];
			int hasCode = 0;
			
			while((hasCode = inputStream.read(bt)) > 0) {
				//防止中文乱码
				System.out.println(new String(bt, 0, hasCode, "UTF-8"));
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException io) {
			io.printStackTrace();
		} finally{
			try {
				//关闭流
				if(inputStream != null) inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
				
	}
	
	//演示字节输出流
	public static void outputStreamTest() {
		InputStream inputStream = null;
		OutputStream out = null;
		
		try {
			inputStream = new FileInputStream("F://test/inputStream.txt");
			out = new FileOutputStream(new File("F://test/outputStream.txt"));
			
			byte bt[] = new byte[1024];
			int length = 0;
			while((length = inputStream.read(bt)) > 0) {
				//写入
				out.write(bt, 0, length);
			}
			
		} catch (IOException io) {
			io.printStackTrace();
		} finally {
			try {
				//关闭流
				if(out != null) out.close(); 
				if(inputStream != null) inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
	//测试字符输入流
	public static void testReader() {
		Reader r = null;
		
		try {
			r = new FileReader(new File("F://test/reader.txt"));
			char ch[] = new char[1024];
			int length = 0;
			while((length =r.read(ch) ) != -1) {
				
				System.out.println("测试reader:" + new String(ch));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(r != null) r.close(); 
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}
	
	//测试输出流
	public static void testWriter() {
		Reader r = null;
		Writer wr = null;
		try {
			r = new FileReader(new File("F://test/reader.txt"));
			wr = new FileWriter(new File("F://test/writer.txt"));
			
			int length = 0;
			while((length = r.read()) != -1) {
				wr.write(length);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				if(wr != null) wr.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	} 

    我将上面的方法都写成了静态,方便我的调用测试,有兴趣的同学可以写一些demo做一下自己的测试.

    上面的流都是通过OS底层直接处理的,这样就会导致一个问题,每次写入和写出的时候都会耗费大量的资源,导致性能十分低下.因此我们能不能一次读取一行或者一部分文件呢?BufferedReader和BufferedWriter的出现便是为了解决这个问题.他们都是将写入或者写出的数据存入一个缓存中,只有当缓存慢的时候才会写入内存或者写出内存.下面为大家展示一些demo:

//测试缓存字节输入流
	public static void testBufferedInputStream() {
		InputStream input = null;
		BufferedInputStream bufInputStream = null;
		
		try {
			input = new FileInputStream(new File("D://打包/test/bufferedInput.txt"));
			bufInputStream = new BufferedInputStream(input);
			
			byte bt[] = new byte[1024];
			int len = 0;
			StringBuilder sbBuilder = new StringBuilder();	
			while((len = bufInputStream.read(bt)) != -1) {
				sbBuilder.append(new String(bt, 0, len, "UTF-8"));
			}
			
			System.out.println("输出层:::" + sbBuilder);
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch (IOException e1) {
			e1.printStackTrace();
		} finally {
			try {
				if(bufInputStream != null) bufInputStream.close(); 
				if(input != null) input.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
	}
						
	//测试缓存字节输出流
	public static void testBufferedOutputStream() {
		InputStream input = null;
		BufferedInputStream bufInputStream = null;
		OutputStream outputStream = null;
		BufferedOutputStream buf = null;
		try {
			input = new FileInputStream(new File("D://打包/test/bufferedInput.txt"));
			bufInputStream = new BufferedInputStream(input);
			
			outputStream = new FileOutputStream(new File("D://打包/test/bufferedOutput.txt"));
			buf = new BufferedOutputStream(outputStream);
			
			byte bt[] = new byte[1024];
			int len = 0;
			
			while((len = bufInputStream.read(bt)) != -1) {
				buf.write(bt, 0, len);
			}
			
			buf.flush();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch (IOException e1) {
			e1.printStackTrace();
		}finally{
			try {
				if(buf != null) buf.close();
				if(bufInputStream != null) bufInputStream.close();
				if(input != null) input.close();
				if(outputStream != null) outputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}			
		
	//测试缓存字符流输入输出
	public static void testReaderAndWriter() {
		Reader reader = null;
		BufferedReader bufferedReader = null;
		Writer writer = null;
		BufferedWriter bufferedWriter = null;
		
		try {
			reader = new FileReader(new File("D://打包/test/bufferedReader.txt"));
			bufferedReader = new BufferedReader(reader);
			writer = new FileWriter(new File("D://打包/test/bufferedWriter.txt"));
			bufferedWriter = new BufferedWriter(writer);
			
			String line = null;
			
			while((line = bufferedReader.readLine()) != null) {
				bufferedWriter.write(line.toUpperCase());
				bufferedWriter.newLine();
				bufferedWriter.flush();
			}
			
		} catch (FileNotFoundException fn) {
			fn.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				//BufferedReader装饰一个 Reader使之具有缓冲功能,
				//要关闭只需要调用最终被装饰出的对象的 close()方法即可,因为它最终会
				//调用真正数据源对象的 close()方法。因此,可以只调用外层流的close方法关闭其装饰的内层流
				if(bufferedWriter != null) bufferedWriter.close();
				if(bufferedReader != null) bufferedReader.close(); 
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
		
	//文件的写入写出整合
	public static void testReaderWriterWithUnicode() {
		File file = new File("D://打包/test/测试.txt");
		
		InputStreamReader reader = null;
		BufferedReader bufferedReader = null;
		OutputStreamWriter writer = null;
		BufferedWriter bufferedWriter = null;
		
		try {
			if(!file.exists()) {
				file.createNewFile();
			}
			
			reader = new InputStreamReader(new FileInputStream("D://海典文件整理/药店加公众号和第三方/微信秘钥/药店加公众号秘钥.txt"), "UTF-8");
			bufferedReader = new BufferedReader(reader);
			
			writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
			bufferedWriter = new BufferedWriter(writer);
			
			String line = null;
			while((line = bufferedReader.readLine()) != null) {
				bufferedWriter.write(line);
				bufferedWriter.newLine();
			}
			bufferedWriter.flush();
			
		} catch (IOException io) {
			io.printStackTrace();
		} finally {
			try {
				if(bufferedWriter != null) bufferedWriter.close();
				if(bufferedReader != null) bufferedReader.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}	
		
	//图片写入写出
	public static void testImageIO() {
		//FileImageInputStream fis = null;
		//FileImageOutputStream fos = null;
		
		FileInputStream fis = null;
		FileOutputStream fos = null;
		
		try {
			//fis = new FileImageInputStream(new File("D://海典文件整理/美女.jpg"));
			//fos = new FileImageOutputStream(new File("D://打包/test/美女.jpg"));
			fis = new FileInputStream(new File("D://海典文件整理/美女.jpg"));
			fos = new FileOutputStream(new File("D://打包/test/美女1.jpg"));
			
			byte read[] = new byte[1024];
			int len = 0;
			
			while((len = fis.read(read)) != -1) {
				fos.write(read, 0, len);
			}
			
			fos.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(fos != null) fos.close();
				if(fis != null) fis.close(); 
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}	

    注意事项:我们在写入和写出流的时候需要在使用完之后,将其关闭,不然使用他们是一个十分耗资源的事情.另外,写出流关闭的时候, 要确认其已经写出完毕,因此一般我们都会在关闭前调用flush()方法来确保.同时,在遇到换行的时候,调用newline()方法.

    read和readline的区别:

    read是通过判断其返回值是否为-1来确保是否读取完毕的,其是通过字节来来读取的,readline()表示读取的是一段,通常默认值是8192个字节大小,其内部是一个阻塞函数,当没有读取的时候不会返回null,只有发生异常或者另一端被关闭的时候,才会返回null.其在读取效率的时候不如定义一个大小为8192的数组,因为buffered内部是定义两个这样大小的数组.

  IO是阻塞的流,NIO则是非阻塞的,本文只是对其进行简单的介绍,详情会在后续的关于socket博文中进行研究:

   NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值