Java 流(Stream)和IO

Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。

Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。

Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。

流:  流的作用,流的特点,流的功能,流的使用
		1.节点流:最基本完成读入写出功能
			1)字节流  : 万能流   *******
				 FileInputStream | FileOutputStream	-->文件操作
				   字节数组流(了解),字节节点流  不是操作文件,不是读入写出文件,而是读入字节数组中的内												      
				   容,写出到字节数组  
				   ByteArrayInputStream  ByteArrayOutputStream
			2)字符流  :纯文本  
				FileReader   FileWriter
		2.功能流(节点流):
			1)缓冲流 : 提高节点流的功能和读写效率
				字节缓冲流--没有新增方法
				字符缓冲流--有新增方法,读取一行,插入换行符
			2)转换流:字节->字符
				InputStreamReader  OutputStreamWriter
			3)data流(字节节点流[文件|字节数组]):读写保留基本数据类型+字符串
				DataInputStream   DataOutputStream  新增方法:readXxx()  writeXxx()
			4)对象流(字节节点流[文件|字节数组]):读写对象类型信息
				ObjectInputStream ObjectOutputStream  新增方法:readXxx()  writeXxx()

字节流

字节输入流FileInputStream:

/*
 * 目的:操作文件内部的内容,读,写...
 *  流:一连串流动的数据,管道,具有先入先出的规律..
 *  IO流:学习不同的流,达到写出写出,上传下载的过程
 *  数据源头   ----->   目的地
 *  流的分类:
 *  	方向划分: 以程序为中心
 *  		输入流
 *  		输出流
 *  	操作单元:
 *  		字节流:万能流***
 *  		字符流
 *  	功能:
 *  		节点流: 直接从数据源到目的地
 *  		功能流|包装流:从数据源出来的数据经过一些包装,增强某些功能到目的地
 *  	流的分类之间都是相辅相成的
 *  
 *  字节流:万能流  *****
 *  	字节输入流   InputStream 抽象类 -> 子类FileInputStream文件字节输入流   
 											读read()+close()关闭
 *  	
 */
//字节流  万能流  读入
public class IODemo01 {
	public static void main(String[] args) throws IOException {
        //1.通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例,建立要读入文件与程序的联系
		File src=new File("D:/haha/heihei.txt");
		//2.打开一个到实际文件的连接来创建一个流  抽象类多态(接口与实现类的方法相同,实现类新增方法对接口													不可见)
		InputStream is=new FileInputStream(src);
		//3.调用流的方法read,读数据,利用数组存值,循环读入
		byte[] car=new byte[1024];//声明数组,一般为1024的整数倍
		//read(byte[])-->返回值:读入到字节数组中的数据的个数
		//从此输入流中将 byte.length 个字节的数据读入一个 byte 数组中。在某些输入可用之前,此方法将阻			塞。 
		//读入缓冲区的字节总数,如果因为已经到达流末尾而没有更多的数据,则返回 -1。 
		//如果一个数组读不完,重复循环的读入
		int len=-1;  //定义读入到数组中的数据的个数
		while((len=is.read(car))!=-1){
			System.out.print(new String(car, 0, len));
		}
		//4.关闭流
		is.close();
	}
}

字节输出流FileOutputStream:

/*
 * 文件字节输入流--读入
 * 文件字节输出流--写出
 * 	OutputStream  抽象类-->FileOutputStream 字节文件输出流
 * 输出流: 写出-->刷出-->关闭
 * 
 * 覆盖问题:写出默认覆盖原文件中的内容,如果想要追加,可以构造器中添加boolean append,true追加,false不追加,覆盖,默认false
 */
//写出
public class IODemo02 {
	public static void main(String[] args) throws IOException {
		//1.通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例,建立要读入文件与程序的联系
		File f=new File("D:/haha/heihei.txt");
		//2.选择写出流
		//FileOutputStream(File file, boolean append)  创建一个向指定 File 对象表示的文件中写入															数据的文件输出流。
		//boolean append,true追加,false不追加则覆盖,默认false
		OutputStream out=new FileOutputStream(f,true);
		//3.写出到文件
		out.write(100);
		//4.刷出
		out.flush();
		//5.关闭
		out.close();
	}
}
字节输出流FileOutputStream写出多个数据:
/*
 * 一个字节一个字节写出,效率低,想要写出多个数据,可以写出一个字节数组的数据  write(byte[]) 将数组写出到		输出流中
 */
public class IODemo03 {
	public static void main(String[] args) {
		//流
		OutputStream out=null;
		//目的地:文件不存在,系统会自动创建,如果路径(文件夹)不存在,需要手动创建,否则会报错
		try {
			out=new FileOutputStream("D:/haha.txt");
			//2.写出
			//准备数据
			String str="bxn";
			byte[] b=str.getBytes();
			out.write(b);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
            	增强程序的健壮性
				try {
					if(out!=null){
					out.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}	
		}
	}
}
封装拷贝文件的工具类:
public class CopyUitls {
	//拷贝文件   参数:2个  数据源   目的地
	public static void copyFile(String src,String dest){
		copyFile(new File(src),new File(dest));
	}
	public static void copyFile(File src,File dest){
		//1.建立联系(数据源.目的地)
		//2.创建流 
		InputStream is=null;
		OutputStream os=null;
		
		try {
			is=new FileInputStream(src);//数据源
			os=new FileOutputStream(dest);//目的地
			
			//3.读入写出
			//准备数组
			byte[] car=new byte[1024];
			int len=-1; //读入到数组中数据的个数
			while((len=is.read(car))!=-1){
				os.write(car, 0, len);
			}
			
			//4.刷出
			os.flush();
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  finally{
			//5.关闭(后打开的先关闭,先打开的后关闭)
			if(null!=os){
				try {
					os.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(null!=is){
				try {
					is.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}	
}

字符流

字符流 :只能操作纯文本的内容…

字符输入流FileReader:

字符输入流 Reader 抽象类 FileReader 文件字符输入流

流向:输入流 功能:节点流 操作单元:字符流

public class IODemo01 {
	public static void main(String[] args) {
		//1.建立联系+选择流
		Reader read=null;
		try {
			read=new FileReader("D:/lalala.txt");
			//2.读入
			//System.out.println((char)read.read());
			char[] car=new char[1024];
			//int len=read.read(car);
			int len=0;  //读入到字符数组中的字符个数
			while((len=read.read(car))!=-1){
				System.out.println(new String(car,0,len));
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			//3.关闭
			try {
				if(read!=null){
					read.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}		
	}
}

字符输出流FileWriter:

字符输出流: Writer 抽象类 FileWriter 文件字符输出流

流向:输出流 操作单元:字符流 功能:节点流

没有新增方法可以发生多态

public class IODemo02 {
	public static void main(String[] args) {
		//1.选择流
		Writer wr=null;
		try {
			wr=new FileWriter("D:/lalala.txt",true);   //默认false不追加
			//2.准备数据+写出
			//数据
			String str="哈哈哈,今天是周六啦!!!";
			char[] car=str.toCharArray();
			//wr.write(str);
			//wr.write(str,2,4);
			//wr.write("\n");  //系统文件中打开没效果,工具中打开有效果
			wr.write("\r\n");  //windows操作系统识别换行,工具中打开有效果
			wr.write(car,0,car.length);
			//3.flush
			wr.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally{
			//4.关闭
			try {
				//选中多行,alt+shift+z
				if(wr!=null){
					wr.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

缓冲流

缓冲流 ->功能流的一种: 增强性能,提高功能,提高读写速度…

功能流使用: 功能流(节点流)

字节输入/输出缓冲BufferedInputStream/BufferedOutputStream:

字节输入缓冲流(字节输入流) BufferedInputStream

字节输出缓冲流(字节输出流) BufferedOutputStream

没有新增方法,可以换使用多态

public class BufferedInputStream01 {
	public static void main(String[] args) throws IOException {
		InputStream is=new BufferedInputStream(new FileInputStream("D://hehe.txt"));
		OutputStream os=new BufferedOutputStream(new FileOutputStream("D:/haha.txt"));
		byte[] car=new byte[1024];
		int len=0;
		while(-1!=(len=is.read(car))){
			os.write(car, 0, len);
		}
		os.flush();
		os.close();
		is.close();
	}
}

*字符输入/输出缓冲流BufferedReader/BufferedWriter:

字符输入 缓冲流 BufferedReader 功能:功能流 流向:输入流 操作单元:字符流

新增方法:String readLine() 读取一个文本行。

字符输出缓冲流 BufferedWriter

新增方法: void newLine() 写入一个行分隔符。

存在新增方法,不能多态使用

public class BufferedReader02 {
	public static void main(String[] args) {
		//1.声明流
		BufferedReader rd=null;
		BufferedWriter rt=null;
		try {
			rd=new BufferedReader(new FileReader("D:/hehe.txt"));
			rt=new BufferedWriter(new FileWriter("D:/xixi.txt"));
			//2.读入写出
			//char[] car=new char[1024];
			String msg=null; //存储的是读取到的每行内容
			while(null!=(msg=rd.readLine())){
				rt.write(msg);
				rt.newLine();
			}
			//3.刷出
			rt.flush();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally{
			//4.关闭
			try {
				if(rt!=null){
					rt.close();
				}
				if(rd!=null){
					rd.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

转换流

需求: 想要把字节转为字符,或者已有字节流,想要使用字符流的功能,可以进行转换

转换流: 功能流(节点流): 把字节流转换为字符流

字节输入转换流:InputStreamReader(InputStream,“编码格式”) -->Reader

字节输出抓换流:OutputStreamWriter(OutputStream,“编码格式”)–>Writer

public class ConvertDemo02 {
	public static void main(String[] args) throws IOException {
		//1,流
		BufferedReader read=new BufferedReader(new InputStreamReader(new 				 BufferedInputStream(new FileInputStream("D:/haha.txt"))));
		BufferedWriter write=new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("D:/heihei.txt",true))));
		//2.读写
		String msg=null;
		while((msg=read.readLine())!=null){
			write.write(msg);
			write.newLine();
		}
		//3.刷出
		write.flush();
		//4.关闭
		write.close();
		read.close();
	}
}

data数据流

基本数据类型流 Data流|数据流: 功能流(节点流)

功能:读写带有基本数据类型的数据+String

DataInputStream(InputStream) 新增方法: readXxx() 读入java基本类型的数据

DataOutputStream(OutputStream) 新增方法: writeXxx() 写出java基本类型的数据

注意:什么顺序写出,什么顺序读入

可能遇到异常EOFException:文件存在,内容无法读取

public class DataDemo03 { 
	public static void main(String[] args) throws IOException {
		//write("D:/aaa.txt");
		read("D:/aaa1.txt");
	}
	
	//读入
	public static void read(String pathName) throws IOException{
		//输入流
		DataInputStream is=new DataInputStream(new BufferedInputStream(new FileInputStream(pathName)));
		//读入
		int i=is.readInt();
		boolean b=is.readBoolean();
		String s=is.readUTF();
		System.out.println(i+"-->"+b+"-->"+s);
		//关闭
		is.close();
	}

	//写出带有基本数据类型的数据
	public static void write(String pathName) throws IOException{
		//输出流
		DataOutputStream out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(pathName)));
		//数据
		int i=101;
		boolean b=false;
		String str="haha";
		//写出
		out.writeInt(i);
		out.writeBoolean(b);
		out.writeUTF(str);
		//刷出
		out.flush();
		//关闭
		out.close();
	}
}

对象流

对象流: 保留数据+数据类型

对象流(节点流)

序列化:把对象的信息状态,变为可存储|可传输的过程
序列化输出流 ObjectOutputStream(OutputStream)
新增方法: void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。

反序列化输入流 ObjectInputStream(InputStream)

注意:

1.不是所有类型的对象都能序列化 需实现java.io.Serializable

2.先序列化后反序列化 写出读入的过程一致

3.不是对象的所有属性都需要序列化 被transient修饰的属性不能被序列化

4.static不能被序列化

5.如果父类实现了Serializable接口,子类中所有内容都能序列化

6.如果父类没有实现,子类实现了Serializable接口,只能序列化子类中独有的内容

public class ObjectDemo04 {
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		write("D:/bbb.txt");
		read("D:/bbb.txt");
	}
	
	//读入对象信息
	public static void read(String pathName) throws FileNotFoundException, IOException, ClassNotFoundException{
		//流
		ObjectInputStream is=new ObjectInputStream(new BufferedInputStream(new FileInputStream(pathName)));
		//读
		Person obj1=(Person)(is.readObject());//将序列化的对象信息读入程序,并用对应类型接收
		String[] obj2=(String[])(is.readObject());
		System.out.println(obj1+"-->"+Arrays.toString(obj2));
		//关闭
		is.close();
	}
	
	//写出对象信息
	public static void write(String pathName) throws FileNotFoundException, IOException{
		//构建流
		ObjectOutputStream wr=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(pathName)));
		Person p=new Person("李毅",25,"hehe");
		String[] arr={"呵呵","哈哈"};
		//写出
		wr.writeObject(p);
		wr.writeObject(arr);
		
		p.setName("老裴");
		p.haha="lllllllllll";
		//刷出
		wr.flush();
		//关闭
		wr.close();
	}
}
//创建javabean类实现Serializable接口
class Person implements Serializable{
	private String name;
	private transient int age;
	static String haha="123345";
	public Person() {
		// TODO Auto-generated constructor stub
	}
	public Person(String name, int age,String haha) {
		super();
		this.name = name;
		this.age = age;
		this.haha=haha;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Person [name=" + name + ","+age+","+haha+"]";
	}	
}

乱码问题

1.编码和解码格式统一

2.长度丢失问题

public class Demo01 {
	public static void main(String[] args) throws UnsupportedEncodingException {
		/*  中文:     所占字节数
		 * ISO8859-1   1个
		 * UTF-8       3个
		 * GBK		   2个
		 * GB2312      2个
		 */
		System.out.println("好".getBytes("ISO8859-1").length);
		System.out.println("好".getBytes("UTF-8").length);
		System.out.println("好".getBytes("GBK").length);
		System.out.println("好".getBytes("GB2312").length);
		
		byte[] arr="你好".getBytes("GBK");//编码
		System.out.println(Arrays.toString(arr));
		System.out.println(new String(arr,"GBK"));//解码为字符串
	}
}