关于CodeJava的学习笔记——9
一、IO流
1、定义
I=Input=输入 O=Output=输出
流 : 数据从源点传输到汇点的"管道"而已
2、流的分类
按照方向分: 输入流 输出流 *:参照物=当前Java程序为参照物
按照单位分: 字节流 字符流
按照功能分: 节点流 过滤流(包装流 处理流)
3、各种流
(1)基础IO流
InputStream 所有字节输入流统一的父类 抽象类
        int read()
         int read(byte[] data)
         int read(byte[] data,int offset,int length)
OutputStream 所有字节输出流统一的父类 抽象类
        write(int data)
         write(byte[] data)
         write(byte[] data,int offset,int length)
(2)File
FileInputStream 输入流 字节流 节点流
可以自动创建新的文件。如果指向的文件不存在
FileOutputStream 输出流 字节流 节点流(但是只能连接文件 不能连接目录)
会直接替换掉这个文件,然后往文件内部转数据
import java.io.*;
//JDK7.0 出现的 TWR => Try-With-Resources
public class TestFileCopyWithTWR{
	public static void main(String[] args){
		try(FileInputStream fis = new FileInputStream("1.mp3");
			FileOutputStream fos = new FileOutputStream("3.mp3")){
			byte[] data = new byte[5<<20];//5m
			int len;
			while((len = fis.read(data))!=-1){
				fos.write(data,0,len);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}(3)Buffered
BufferedInputStream 输入流 字节流 过滤流
BufferedOutputStream 输出流 字节流 过滤流
作为过滤流的它们 是给原本的流添加缓冲空间
从而提高每次读写的吞吐量 进而提高效率
默认8192 也就是8k 可以传参指定大小
import java.io.*;
public class TestBufferedStream{
	public static void main(String[] args)throws Exception{
		FileInputStream fis = new FileInputStream("1.mp3");//针头
		BufferedInputStream bis = new BufferedInputStream(fis,5<<20);//针管(针头)
		FileOutputStream fos = new FileOutputStream("3.mp3");//针头
		BufferedOutputStream bos = new BufferedOutputStream(fos,5<<20);//针管(针头)
		int data;
		while((data = bis.read())!=-1){
			bos.write(data);
		}
		bos.flush();
		//bos.close();
		bis.close();
	}
}(4)Data
DataInputStream 输入流 字节流 过滤流
DataOutputStream 输出流 字节流 过滤流
为了给原本的流,添加读写基本数据类型的功能
    *: DataInputStream 提供的核心方法 readXxxx() 有返回值
     *: DataOutputStream 提供的核心方法 writeXxxx() 要参数
import java.io.*;
public class HelloWorld{
	public static void main(String[] args)throws Exception{
		int time = 1;
		File dataFile = new File("cs.data");
		if(dataFile.exists()){
			DataInputStream dis = new DataInputStream(new FileInputStream(dataFile));
			time = dis.readInt();
			dis.close();
		}
		System.out.println("HelloWorld : "+time);
		time++;
		//存档的逻辑
		DataOutputStream dos = new DataOutputStream(new FileOutputStream(dataFile));
		dos.writeInt(time);
		dos.close();
	}
}(5)Object
ObjectInputStream 输入流 字节流 过滤流
ObjectOutputStream 输出流 字节流 过滤流
    *: 想要持久化 首先需要序列化
         想要被保存到磁盘当中的对象它的类必须实现序列化接口
             implements Serializable
         如果这个类型当中有其它引用类型的属性
         就连属性的类型也必须要实现序列化接口
         如果某些属性无关紧要 不需要参与持久化存储
         则可以使用transient修饰
             transient => 不参与持久化的
import java.io.*;
public class TestObjectStreamMax{
	public static void main(String[] args)throws Exception{
		/*
		Teacher tea = new Teacher("JayZhou",37);
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("电冰箱.data"));
		oos.writeObject(tea);
		oos.close();
		*/
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("电冰箱.data"));
		Teacher tea = (Teacher)ois.readObject();
		ois.close();
		System.out.println(tea.name + " : " + tea.age + " : " +tea.pc);
	}
}
class Computer{
	String logo;
	public Computer(String logo){
		this.logo = logo;
	}
}
class Teacher implements Serializable{//标识接口
	String name;
	int age;
	//transient => 短暂的 转瞬即逝的 => 不参与持久化的
	transient Computer pc;
	public Teacher(String name,int age){
		this.name = name;
		this.age = age;
		pc = new Computer("Lenovo");
	}
}
4、small big one
import java.io.*;
import java.util.*;
/*
	请用程序找出c盘下的所有.jpg图片 (包含子目录中的哦)
		然后用刚学的内容 将每张图片都复制到d:\foto目录当中
			*: d盘下的foto目录可能尚不存在 得用程序建
			*: c盘下的不同的子目录当中 可能会有重名的文件
					目标目录当中的文件 请以序列编号命名
						00001.jpg
						00002.jpg
						00003.jpg
*/
public class SmallOne{
	static int id; // 用于生成文件名的序列号
	static List<File> list = new ArrayList<>(); // 存储找到的.jpg文件列表
	public static void main(String[] args){
		search(new File("c:\\")); // 从C盘根目录开始搜索
		sortList(); // 对找到的文件按最后修改时间排序
		createTarget(); // 创建目标目录
		for(File src : list){ // 遍历所有找到的文件
			File tar = nextFile(); // 获取下一个目标文件名
			copy(src,tar); // 复制文件
		}
	}
	// 复制文件的方法
	public static void copy(File src,File tar){
		try(FileInputStream fis = new FileInputStream(src); // 输入流读取源文件
			FileOutputStream fos = new FileOutputStream(tar)){ // 输出流写入目标文件
			byte[] data = new byte[16384]; // 缓冲区大小为16KB
			int len;
			while((len = fis.read(data))!=-1){ // 循环读取数据
				fos.write(data,0,len); // 写入数据到目标文件
			}
		}catch(Exception e){
			e.printStackTrace(); // 捕获并打印异常信息
		}
	}
	// 生成下一个目标文件名的方法
	public static File nextFile(){
		StringBuffer buff = new StringBuffer(String.valueOf(++id)); // 序列号自增并转换为字符串
		while(buff.length() < 5){ // 确保文件名长度为5位,不足则补零
			buff.insert(0,"0");
		}
		buff.append(".jpg"); // 添加文件扩展名
		File x = new File("d:\\foto",buff.toString()); // 创建目标文件对象
		return x; // 返回目标文件对象
	}
	// 创建目标目录的方法
	public static void createTarget(){
		File dir = new File("d:\\foto"); // 目标目录路径
		dir.mkdirs(); // 创建目录及其父目录(如果不存在)
	}
	// 对找到的文件列表进行排序的方法
	public static void sortList(){
		list.sort((a,b) -> Long.compare(a.lastModified(),b.lastModified())); // 按最后修改时间升序排序
	}
	// 递归搜索指定目录下的所有.jpg文件的方法
	public static void search(File tar){
		File[] ds = tar.listFiles((x) -> x.isDirectory()); // 获取当前目录下的所有子目录
		File[] js = tar.listFiles((x) -> x.isFile() && x.getName().toLowerCase().endsWith(".jpg")); // 获取当前目录下的所有.jpg文件
		if(ds == null) return; // 如果当前目录没有子目录,直接返回
		for(File d : ds){ // 递归搜索每个子目录
			search(d);
		}
		Collections.addAll(list,js); // 将找到的.jpg文件添加到列表中
	}
}