io流的概述及字节流相关类的基本使用和异常处理

IO流

1.概念

	* IO流用来处理设备之间的数据传输
	* Java对数据的操作是通过流的方式
	* Java用于操作流的类都在IO包中
	* 流按流向分为两种:输入流,输出流。
	* 流按操作类型分为两种:
		* 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
		* 字符流 : 字符流只能操作纯字符数据,比较方便。

2.IO流常用父类

* 字节流的抽象父类:
		* InputStream 
		* OutputStream
* 字符流的抽象父类
		* Reader 
		* Writer		

3.IO程序书写

	* 使用前,导入IO包中的类
	* 使用时,进行IO异常处理
	* 使用后,释放资源


类 InputStream

java.lang.Object
——java.io.InputStream
所有已实现的接口: 
Closeable 
直接已知子类: 
AudioInputStream, ByteArrayInputStream, FileInputStream,
InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, 
StringBufferInputStream 

public abstract class InputStreamextends Objectimplements Closeable
	此抽象类是表示字节输入流的所有类的超类。 
	需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法。  


类 OutputStream

java.lang.Object
——java.io.OutputStream
所有已实现的接口: 
Closeable, Flushable 
直接已知子类: 
ByteArrayOutputStream, FilterOutputStream, ObjectOutputStream,
 OutputStream, PipedOutputStream 

public abstract class OutputStreamextends Objectimplements Closeable, Flushable
	此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。 
	需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。 


类 Reader

java.lang.Object
  java.io.Reader
所有已实现的接口: 
Closeable, Readable 
直接已知子类: 
BufferedReader, CharArrayReader, FilterReader, InputStreamReader, 
PipedReader, StringReader 

public abstract class Reader extends Objectimplements Readable, Closeable
	用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。
	但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。 


类 Writer

java.lang.Object
——java.io.Writer
所有已实现的接口: 
Closeable, Flushable, Appendable 
直接已知子类: 
BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, 
PipedWriter, PrintWriter, StringWriter 

public abstract class Writerextends Object implements Appendable, Closeable, Flushable
	写入字符流的抽象类。
	子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。
	但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。


类 FileInputStream

java.lang.Object
——java.io.InputStream
————java.io.FileInputStream
所有已实现的接口: 
Closeable 

public class FileInputStream extends InputStream

	从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。 
	FileInputStream 用于读取诸如图像数据之类的原始字节流。
 

构造方法

public FileInputStream(File file) throws FileNotFoundException
          通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
	如果指定文件不存在,或者它是一个目录,而不是一个常规文件,抑或因为其他某些原因而无法打开进行读取,则抛出 FileNotFoundException 

public FileInputStream(String name) throws FileNotFoundException
          通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。 
	如果指定文件不存在,或者它是一个目录,而不是一个常规文件,抑或因为其他某些原因而无法打开进行读取,则抛出 FileNotFoundException。 


public int available() throws IOException

	一次读取所有字节,并返回字节数

public int read() throws IOException

	从此输入流中读取一个数据字节。如果没有输入可用,则此方法将阻塞。 
	指定者:
	类 InputStream 中的 read
	返回:
	从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。;如果已到达文件末尾,则返回 -1。 
	抛出: 
	IOException - 如果发生 I/O 错误。

public int read(byte[] b) throws IOException

	从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
	参数:
	b - 存储读取数据的缓冲区。 
	返回:
	读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。 

eg

public class b {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("ccc.txt");	//创建流对象
		int x = fis.read();	//从硬盘上读取一个字节
		System.out.println(x);//a,97
		int y = fis.read();
		System.out.println(y);//98
		int z = fis.read();
		System.out.println(z);//99
		int a = fis.read();
		System.out.println(a);//100
		int b = fis.read();
		System.out.println(b);//-1
		fis.close();	//关流释放资源
		
		
		FileInputStream fistream = new FileInputStream("ccc.txt");	//创建流对象
		int m;
		while((m = fistream.read()) != -1) {
			System.out.println(m);
		}
		fistream.close();
		
	}

}
IO流(read()方法返回值为什么是int?

		因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,
	如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
	那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,
	所以在读取的时候用int类型接收,如果11111111会在其前面补上
	24个0凑足4个字节,那么byte类型的-1就变成int类型的255了
	这样可以保证整个数据读完,而结束标记的-1就是int类型
		一个字节byte是8个二进制位bit,
	文件底层都是以二进制形式的存储的
	00010100 00100100 01000001 11111111 0000000
	10000001    	 byte类型-1的原码
	11111110	    -1的反码(高位不变,其余取反)
	11111111    	-1的补码 (高位不变,取反加1)
	运算时都是用补码进行运算
	如上若用byte则读取不能完成
	若用int四个字节32位
	byte类型-1的补码11111111为
	00000000 00000000 00000000 11111111
	每读一个字节前面补24个0



类 FileOutputStream

java.lang.Object
——java.io.OutputStream
————java.io.FileOutputStream
所有已实现的接口: 
Closeable, Flushable 

FileOutputStream在创建对象的时候是如果没有这个文件会帮我创建出来
如果有这个文件就会先将文件清空


public void write(int b) throws IOException
	将指定字节写入此文件输出流。实现 OutputStreamwrite 方法。 

public void write(byte[] b) throws IOException

	将 b.length 个字节从指定 byte 数组写入此文件输出流中。
 

public void write(byte[] b,int off,int len) throws IOException
	将指定 byte 数组中从偏移量 off(从数组的索引off处)开始的 len 个字节写入此文件输出流。 
 

public class c {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		FileOutputStream fos = new FileOutputStream("cc.txt");	
		//创建字节输出流对象,如果没有就自动创建一个
		fos.write(97);				
		//虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
		fos.write(98);
		fos.write(99);
		fos.write(100);
		fos.close();
		
		FileOutputStream fostream = new FileOutputStream("cc.txt",true);	
		//如果想续写就在第二个参数传true
		fostream.write(97);
		fostream.write(98);
		fostream.close();

	}

}

读取文件然后打印的一个小问题

public static void main(String[] args) throws IOException {
		
		FileInputStream fis = new FileInputStream("cc.txt");
		byte[] arr = new byte[2];
		
		int a = fis.read(arr);//将文件上的字节读取到字节数组中	
		System.out.println(a);//读到的有效字节个数,2
		for (byte b : arr) {	
			System.out.println(b);//第一次获取到的是文件上的a和b,97,98
		}
		
		System.out.println("-----------------------");
		
		int c = fis.read(arr);
		System.out.println(c);//1
		for (byte b : arr) {
			System.out.println(b);//99,98
			/*在arr数组里,第一次读到97,98
			 * arr[]={97,98}
			 * 第二次int c=fis.read(arr)
			 * 只读到99,arr[0]被覆盖
			 * 则arr[]={99,98}
			 * */
		}
		fis.close();

在文件后追加demo

public static void main(String[] args) throws IOException {
		
		FileInputStream fis1 = new FileInputStream("cc.txt");
		FileOutputStream fos1 = new FileOutputStream("cc1.txt");
		
		byte[] arr1 = new byte[2];
		int len;
		while((len = fis1.read(arr1)) != -1) {
			fos1.write(arr1,0,len);
			//把arr1字节数组的0-len个字节写入fos1的末尾
			
		}
		fis1.close();
		fos1.close();
文件拷贝1

public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("h.jpg");	//创建输入流对象,h.jpg
		FileOutputStream fos = new FileOutputStream("copy.jpg");//创建输出流对象,关联copy.jpg
	
		int b;
		while((b = fis.read()) != -1) {	//在不断的读取每一个字节
			fos.write(b);		//将每一个字节写出
		}
		
		fis.close();//关流释放资源
		fos.close();//ok+
文件拷贝2
public static void main(String[] args) throws IOException {
		
		FileInputStream fis1 = new FileInputStream("Eight.mp3");	
		//创建输入流对象,关联Eight.mp3
		FileOutputStream fos1 = new FileOutputStream("copy.mp3");
		//创建输出流对象,关联copy.mp3
		
		int b1;
		while((b1 = fis1.read()) != -1) {//在不断的读取每一个字节
			fos1.write(b1);				//将每一个字节写出
		}
		System.out.print("ok,mp3 finish");
		//开发中不推荐使用,效率太低,每次一个字节,读一次,写一次,花费双倍时间
		//我们需要一个容器,一次拿更多的字节
		fis1.close();//关流释放资源
		fos1.close();
文件拷贝3
public class copy {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		//这种种拷贝,不推荐使用,因为有可能会导致内存溢出
		FileInputStream fis3 = new FileInputStream("Eight.mp3");		
		FileOutputStream fos3 = new FileOutputStream("copy1.mp3");	
		/*int len = fis3.available();
		System.out.println(len);//17577392*/		
		byte[] arr = new byte[fis3.available()];//创建与文件一样大小的字节数组
		//若字节数过大,可能会导致内存溢出
		fis3.read(arr);	//将文件上的字节读取到内存中
		fos3.write(arr);//将字节数组中的字节数据写到文件上
		
		fis3.close();//很快
		fos3.close();
	}

}

文件拷贝3(标准拷贝)

public class d {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		//标准格式
		FileInputStream fis2 = new FileInputStream("Eight.mp3");
		FileOutputStream fos2 = new FileOutputStream("copyi.mp3");
		
		byte[] arr2 = new byte[1024 * 8];//1024的整数倍
		int len2;
		while((len2 = fis2.read(arr2)) != -1) {	
		//如果忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
			fos2.write(arr2,0,len2);
		}
		
		fis2.close();
		fos2.close();

	}

}

BufferedInputStream和BufferOutputStream拷贝

A:缓冲思想
	* 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
	* 这是加入了数组这样的缓冲区效果,java本身在设计的时候,
	* 也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
B.BufferedInputStream
	* BufferedInputStream内置了一个缓冲区(数组)
	* 从BufferedInputStream中读取一个字节时
	* BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
	* 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
	* 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
C.BufferedOutputStream
	* BufferedOutputStream也内置了一个缓冲区(数组)
	* 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
	* 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
D.小数组的读写和带Buffered的读取哪个更快?
	* 定义小数组如果是8192个字节大小和Buffered比较的话
		* 定义小数组会略胜一筹,因为读和写操作的是同一个数组
		* 而Buffered操作的是两个数组


IO流flush和close方法的区别

* flush()方法
	* 用来刷新缓冲区的,将缓冲区的字节全都写到到文件上,刷新后可以再次写出
* close()方法
	* 用来关闭流释放资源的的,
	* 如果是带缓冲区的流对象的close()方法,
	* 不但会关闭流,还会再关闭流之前刷新一次缓冲区,将缓冲区的字节全都刷新到文件上,再关闭,
	* close方法刷完之后就不能写了

在聊天软件开发中,我们常用的是flush()


public class e {

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		
		FileInputStream fis = new FileInputStream("Eight.mp3");
		FileOutputStream fos = new FileOutputStream("copybs.mp3");
		BufferedInputStream bis = new BufferedInputStream(fis);
		//创建缓冲区对象,对输入流进行包装让其变得更加强大
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}

		bis.close();
		bos.close();
	
		
		BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream("Eight.mp3"));
		BufferedOutputStream bos1 = new BufferedOutputStream(new FileOutputStream("copy_bs.mp3"));
		
		int b1;
		while((b1 = bis1.read()) != -1) {
			bos1.write(b1);
		}
		bis1.close();
		bos1.close();
	}


}


 字节流读写中文

* 字节流读取中文的问题
	* 一个中文3个字节(UTF-8)[GBK,一个中文2个字节],字节流在读中文的时候有可能会读到半个中文,造成乱码 
* 字节流写出中文的问题
	* 字节流直接操作的是字节,所以写出中文必须将字符串转换成字节数组 
	* 写出回车换行 write("\r\n".getBytes());

public class f {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("yyy.txt");
		byte[] arr = new byte[3];
		int len;
		while((len = fis.read(arr)) != -1) {
			System.out.println(new String(arr,0,len));//纯中英文可以但加入任何符号就会出错,包括换行符
		}	
		fis.close();
		
		
		FileOutputStream fos = new FileOutputStream("zzz.txt");
		fos.write("我读书少,你不要骗我".getBytes());
		fos.write("\r\n".getBytes());
		fos.write(",骗子".getBytes());
		fos.close();//写完全可以

	}

}
关于中文到流的读写有好多问题,有关编码平台~~

有次开发,别人在前台用gbk码给后台发中文,后台又是用utf-8开发和显示~就是一堆乱码

流的标准异常处理

jdk1.6及之前标准异常处理

public class g {
	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		FileInputStream fis = null;//作用域问题
		FileOutputStream fos = null;
		//null,io局部变量有可能赋值失败,局部变量使用之前要初始化
		//finally不能单独使用
		//IO严谨逻辑,
		try {
			fis = new FileInputStream("xxx.txt");
			fos = new FileOutputStream("yyy.txt");
			
			int b;
			while((b = fis.read()) != -1) {
				fos.write(b);
			}
		}finally {
			try{
				if(fis != null)
					fis.close();
			}finally {	//try fianlly的嵌套目的是能关一个尽量关一个
				if(fos != null)
					fos.close();
			}
		}

	}

}


jdk1.7标准异常处理

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author fish
 *创建时间2017-5-13下午4:44:43
 */
public class h {

	/**1.7版本
	 * 在try()中创建的流对象必须实现了AutoCloseable这个接口,
	 * 如果实现了,在try后面的{}(读写代码)执行后就会自动调用,流对象的close方法将流关掉 
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		try(//流对象写在try()后{}运行完后,流对象自动关闭
				FileInputStream fis = new FileInputStream("ccc.txt");
				FileOutputStream fos = new FileOutputStream("yyy.txt");
				MyClose mc = new MyClose();
			){
				int b;
				while((b = fis.read()) != -1) {
					fos.write(b);
				}
			}

	}

}
//AutoCloseable1.7版本,自动关闭,所有的流都实现了这个接口
class MyClose implements AutoCloseable {
	@Override
	public void close() throws Exception {
		// TODO Auto-generated method stub
		System.out.print("我关了");
	}
	
}

IO流的加密与解密

一个数异或另一个数两次就是它本身

public class i {

	/**
	 * 一个数异或另一个数两次就是它本身
	 * 将写出的字节异或上一个数,这个数就是密钥,解密的时候再次异或就可以了
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		/**
		 * 一个数异或另一个数两次就是它本身
		 * int num = 8;
		 *System.out.println(num ^ 3);//11
		 *System.out.println((num ^ 3) ^ 3);//8
		 **/		
		/*
		 * 加密
		 * */
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("copy.jpg"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("addcopy.jpg"));
		
		int b;
		while((b = bis.read()) != -1) {
			//bos.write(b);
			bos.write(b ^ 123);
		}
		
		bis.close();
		bos.close();
		/*
		 * 解密
		 * */
		BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream("addcopy.jpg"));
		BufferedOutputStream bos1 = new BufferedOutputStream(new FileOutputStream("se_addcopy.jpg"));
		
		int b1;
		while((b1 = bis1.read()) != -1) {
			bos1.write(b1 ^ 123);
		}
		
		bis1.close();
		bos1.close();

	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值