Java--IO流(InputStream,OutputStream,拷贝)

3/8/2017来源:ASP.NET技巧人气:2656

一、IO流概述及其分类

1、概念

IO流用来处理设备之间的数据传输

java对数据的操作是通过流的方式

Java用于操作流的类都在IO包中

流按流向分为两种:输入流,输出流。

流按操作类型分为两种:

字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的

字符流 : 字符流只能操作纯字符数据,比较方便。

2、IO流常用父类

字节流的抽象父类:

InputStream 

OutputStream

字符流的抽象父类:

Reader 

Writer

3、IO程序书写

使用前,导入IO包中的类

使用时,进行IO异常处理

使用后,释放资源

4、read()方法读取的是一个字节,为什么返回是int,而不是byte

因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,

如果每次读取都返回byte,有可能在读到中间的时候遇到111111111

那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,

所以在读取的时候用int类型接收,如果11111111会在其前面补上

24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型

二、字节数组拷贝

1、int read(byte[] b):一次读取一个字节数组

2、write(byte[] b):一次写出一个字节数组

3、available()获取读的文件所有的字节个数

4、小数组

write(byte[] b)

write(byte[] b, int off, int len)写出有效的字节个数

三、BufferedInputStream和BufferOutputStream拷贝

1、缓冲思想

字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,

这是加入了数组这样的缓冲区效果,java本身在设计的时候,

也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流

2、BufferedInputStream

BufferedInputStream内置了一个缓冲区(数组)

从BufferedInputStream中读取一个字节时

BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个

程序再次读取时, 就不用找文件了, 直接从缓冲区中获取

直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个

3、BufferedOutputStream

BufferedOutputStream也内置了一个缓冲区(数组)

程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中

直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里4、小数组的读写和带Buffered的读取哪个更快?

定义小数组如果是8192个字节大小和Buffered比较的话

定义小数组会略胜一筹,因为读和写操作的是同一个数组

而Buffered操作的是两个数组

四、flush和close方法区别

1、close具备刷新功能,在关闭流之前,就会先刷新一次缓冲区,将缓冲区的字节全部刷新到文件上,再关闭,且刷新完之后不能再写了

2、flush具备刷新功能,刷新完之后可以继续写

五、字节流读写中文

字节流读取中文的问题

字节流在读中文的时候有可能会读到半个中文,造成乱码 

字节流写出中文的问题

字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组 

写出回车换行 write("\r\n".getBytes());

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputStreamClass {

	public static void main(String[] args) throws IOException {
		/*
		 	一、IO流概述及其分类
		 	1、概念
				IO流用来处理设备之间的数据传输
				Java对数据的操作是通过流的方式
				Java用于操作流的类都在IO包中
				流按流向分为两种:输入流,输出流。
				流按操作类型分为两种:
					字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
					字符流 : 字符流只能操作纯字符数据,比较方便。
			2、IO流常用父类
				字节流的抽象父类:
					InputStream 
					OutputStream
				字符流的抽象父类:
					Reader 
					Writer		
			3、IO程序书写
				使用前,导入IO包中的类
				使用时,进行IO异常处理
				使用后,释放资源
			4、read()方法读取的是一个字节,为什么返回是int,而不是byte
			   因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,
			如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
			那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,
			所以在读取的时候用int类型接收,如果11111111会在其前面补上
			24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
			二、字节数组拷贝
			1、int read(byte[] b):一次读取一个字节数组
			2、write(byte[] b):一次写出一个字节数组
			3、available()获取读的文件所有的字节个数
			4、小数组
			   write(byte[] b)
			   write(byte[] b, int off, int len)写出有效的字节个数
			三、BufferedInputStream和BufferOutputStream拷贝
			1、缓冲思想
			      字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
			      这是加入了数组这样的缓冲区效果,java本身在设计的时候,
			      也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
			2、BufferedInputStream
			  BufferedInputStream内置了一个缓冲区(数组)
			     从BufferedInputStream中读取一个字节时
			  BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
			     程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
			     直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
			3、BufferedOutputStream
			  BufferedOutputStream也内置了一个缓冲区(数组)
			     程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
			     直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
			4、小数组的读写和带Buffered的读取哪个更快?
				定义小数组如果是8192个字节大小和Buffered比较的话
				定义小数组会略胜一筹,因为读和写操作的是同一个数组
				而Buffered操作的是两个数组
		    四、flush和close方法区别
		    1、close具备刷新功能,在关闭流之前,就会先刷新一次缓冲区,将缓冲区的字节全部刷新到文件上,再关闭,且刷新完之后不能再写了
		    2、flush具备刷新功能,刷新完之后可以继续写
		    五、字节流读写中文
			   字节流读取中文的问题
				  字节流在读中文的时候有可能会读到半个中文,造成乱码 
			   字节流写出中文的问题
				  字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组 
				  写出回车换行 write("\r\n".getBytes());
		 * */
		fileInputStream();//字节输入流
		fileOutputStream();//字节输出流
		copyImages();//复制图片
		littleArray();
		buffer();
		writeChinese();
		exceptionForjdk16();//jdk1.6以及以前版本处理异常
		exceptionForjdk17();//jdk1.7版本处理异常
	}

	public static void exceptionForjdk17() {
		try(FileInputStream fis = new FileInputStream("ccc.txt");
			FileOutputStream fos = new FileOutputStream("ddd.txt");
			//具备自动关闭流的功能
			MyClose myClose = new MyClose();
			/*原理
			在try()中创建的流对象必须实现了AutoCloseable这个接口,如果实现了,在try后面的{}
			(读写代码)执行后就会自动调用,流对象的close方法将流关掉*/
		){
			int b;
			while((b = fis.read()) != -1){
				fos.write(b);
			}
		} catch (FileNotFoundException e) {
			e.PRintStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void exceptionForjdk16() {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try{
			fis = new FileInputStream("aaa.txt");
			fos = new FileOutputStream("bbb.txt");
			int b;
			while((b = fis.read()) != -1){
				fos.write(b);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try{
				if (fis != null)
					fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (fos != null)
					try {
						fos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
			}
		}
	}

	private static void writeChinese() throws IOException {
		FileOutputStream fos = new FileOutputStream("aa.txt");
		fos.write("我读书少".getBytes());
		fos.close();
	}

	private static void buffer() throws IOException {
		FileInputStream fis = new FileInputStream("a.txt");
		FileOutputStream fos = new FileOutputStream("e.txt");
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int b;
		while((b=bis.read()) != -1){
			bos.write(b);
		}
		bis.close();
		bos.close();
	}

	private static void littleArray() throws IOException {
		System.out.println("==============小数组=============");
		FileInputStream fis = new FileInputStream("c.txt");
		FileOutputStream fos = new FileOutputStream("d.txt");
//		byte[] arr = new byte[2];
		byte[] arr = new byte[1024 * 8];//标准写法
		int len;
		while((len = fis.read(arr)) != -1){ //如果此处忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
			fos.write(arr, 0, len);//写入有效文件
		}
		fis.close();
		fos.close();
	}

	private static void copyImages() throws IOException {
		System.out.println("==============拷贝图片=============");
		FileInputStream fis = new FileInputStream("11.jpg");
		FileOutputStream fos = new FileOutputStream("copy.jpg");
		
		//第一种方法:读一点写一点,效率低下
//		int b;
//		while((b = fis.read()) != -1){  //不断的读取每一个字节
//			fos.write(b);   //将字节不断地写出
//		}
//		fis.close();
//		fos.close();
		
		//第二种方法:一次性读出写入,如果内存过大导致内存溢出
		FileOutputStream fos1 = new FileOutputStream("copy1.jpg");
		byte[] arr = new byte[fis.available()];   //创建与文件一样大小的字节数组
		fis.read(arr);            //将文件上的字节数据一次性读取到内存中
		fos1.write(arr);          //将字节数组中的字节数据一次性写到文件上
		fis.close();
		fos1.close();
	}

	private static void fileOutputStream() throws IOException {
		System.out.println("==============字节输出流=============");
		FileOutputStream fis = new FileOutputStream("b.txt",true);
		//如果想续写在第二个参数传true 
		//创建字节流输出对象文件,如果没有自动创建一个;如果有此文件则先将文件清空
		fis.write(97);   //虽然写出的是一个int数,但是到文件上的是一个字节,会自动去掉前三个8位
//		fis.write(98);
//		fis.write(99);
		fis.write(100);
		fis.close();
	}

	public static void fileInputStream() throws FileNotFoundException, IOException {
		System.out.println("==============字节输入流=============");
		FileInputStream fis = new FileInputStream("a.txt");
		int b;
		while((b = fis.read()) != -1){   //文件结束标记为-1
			System.out.print(b +" ");
		}
		fis.close();// 关流释放资源
		System.out.println();
	}
}

class MyClose implements AutoCloseable{
	public void close(){
		System.out.println("我调用了close方法");
	}
}