**数据源**data source,提供数据的原始媒介。常见的数据源有:数据库、文件、其他程序、内存、网络连接、IO设备。数据源分为:源设备、目标设备。<br /> **流**是一个抽象、动态的概念,是一连串连续动态的数据集合。
IO可以理解成bio
- BIO:同步阻塞IO。一个线程触发io操作后必须等待这个io操作执行完成,期间不能去做其它的事
- NIO:同步非阻塞。一个线程触发io操作后它可以立即返回,但是需要不断地去获取执行结果
- AIO:异步非阻塞。一个线程触发io操作后它可以立即返回去做其它工作,内核系统将io操作执行完成后会通知该线程
流的概念细分
按流的方向分类:
1. 输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。
2. 输出流:数据流向是程序到目的地(以OutPutStream、Writer结尾的流)。
按处理的数据单元分类:
1. 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。
2. 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。
按处理对象不同分类:
1. 节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等。
2. 处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。
节点流处于IO操作的第一线,所有操作必须通过它们进行; 处理流可以对节点流进行包装,提高性能或提高程序的灵活性。
四大抽象类
| 抽象类 | 说明 | 常用方法 |
|---|---|---|
| InputStream | 字节输入流的父类,单位字节 | - int read(); - void close(); |
| OutputStream | 字节输出流的父类,单位字节 | - void write(int); - void flush(); - void close(); |
| Reader | 字符输入流的父类,单位字符 | - int read(); - void close(); |
| Writer | 字符输出流的父类,单位字符 | - void write(string); - void flush(); - void close(); |
FileInputStream
通过字节的方式读取文件,适合读取所有类型的文件
////写入字节流 按字段读取public class ReadTxt {public static void main(String[] args) {File file2 = new File("a.txt");FileInputStream in2 = null;try {in2 = new FileInputStream(file2);//缓冲容器 接收字节数组byte[] temp = new byte[5];int len=-1; //接收长度//read( byte[]): 返回读入缓冲区的字节总数,到末尾返回-1while((len = in2.read(temp)) != -1) { //in2把字节读入到temp中//字节数组到字符(使用默认字符集解码指定的 byte 子数组)String s1 = new String(temp,0,len);System.out.println(s1);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if(in2 != null) {in2.close();}} catch (IOException e) {e.printStackTrace();}}}}
FileOutputStream
通过字节的方式写数据到文件中,适合所有类型的文件
//写出字节流public class OutStream {public static void main(String[] args) {File f1 = new File("t3.txt");OutputStream os1 = null;try {os1 = new FileOutputStream(f1);String s1 = "IO stream";byte[] dates = s1.getBytes();//字符串到字节数组(编码)os1.write(dates, 0, dates.length);os1.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}
文件的拷贝
//文件的拷贝public static void copy(String srcpath,String destpath) {File src = new File(srcpath); //源头File dest = new File(destpath); //目的地InputStream in1 = null;OutputStream os1 = null;try {in1 = new FileInputStream(src);os1 = new FileOutputStream(dest);byte[] temp = new byte[10]; //缓冲容器int len =-1;while((len=in1.read(temp))!= -1) { //read方法已将它转为字节os1.write(temp,0,len); //write方法直接写出字节os1.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//释放资源 分别关闭 先打开的后关闭try {os1.close();} catch (IOException e) {e.printStackTrace();}try {in1.close();} catch (IOException e) {e.printStackTrace();}}}
FileReader
通过字符的方式读取文件
文件字符输入流
//文件字符流(可输出文字)public class CharStream {public static void main(String[] args) {File f1 = new File("a.txt");Reader read= null;try {read = new FileReader(f1);char[] temp = new char[1024]; //缓冲容器int len =-1;while((len=read.read(temp))!= -1) {//字符数组到字符串//String str = new String(temp,0,len);System.out.println(str);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if(read!=null) {read.close();}} catch (IOException e) {e.printStackTrace();}}}}
FileWriter
通过字节的方式或追加数据到文件中,仅适合字符文件
文件字符输出流
//FileWriterpublic class CharOutStream {public static void main(String[] args) {File f1 = new File("a.txt");FileWriter fw1 = null;try {fw1 = new FileWriter(f1);/*法1String str1 = "开心每一天";char[] date = str1.toCharArray();//字符串转换成字符数组fw1.write(date,0,date.length);*//*法2 直接写入字符串String str1 = "开心每一天";fw1.write(str1);*///法3fw1.append("一天").append("快乐");//字符读取不够整个数组长度时 不会写入文件中 要刷新一下fw1.flush();} catch (IOException e) {e.printStackTrace();}finally {try {if(fw1!=null) {fw1.close();}} catch (IOException e) {e.printStackTrace();}}}}
ByteArrayInputStream和ByteArrayOutputStream
经常用在需要流和数组之间转化的情况,字节数组是二进制,转换后方便网络传输
注:在内存里运行,适用于量小的字节数据
字节数组输入流
//字节数组输入流public class ByteArrayStream {public static void main(String[] args) throws IOException {byte[] src = "abcde".getBytes();//字符串转换成字节数组InputStream in1 = null;in1 = new ByteArrayInputStream(src); //字节数组byte[] temp =new byte[5];int len = -1;while((len=in1.read(temp))!=-1) {//转回字符串输出String str1 = new String(temp,0,len);System.out.println(str1);}}}
字节数组输出流
//字节数组输出流public class ByteoutStream {public static void main(String[] args) throws IOException {byte[] dest = null;ByteArrayOutputStream b1 = null;b1 = new ByteArrayOutputStream();//不用指定目的地 内存会自动分配//写出操作String str1 = "abcdefg";byte[] dates = str1.getBytes(); //字符串写入字节数组b1.write(dates, 0, dates.length);b1.flush();//使用toByteArray() 或 tostring() 检索数据dest = b1.toByteArray();System.out.println(dest.length+"--"+new String(dest,0,b1.size()));}}
练习:图片的写入写出
public class ByteStream2 {public static void main(String[] args) {byte[] data = filetoByte("1.jpg");System.out.println(data.length);Bytetofile(data,"3.jpg");}//图片到字节数组中public static byte[] filetoByte(String filepath) {File f1 = new File(filepath);byte[] dest = null;InputStream in1 = null;ByteArrayOutputStream b1 = null;try {in1 = new FileInputStream(f1);b1 = new ByteArrayOutputStream();byte[] temp = new byte[1024];int len =-1; //接收长度while((len=in1.read(temp))!=-1) {b1.write(temp,0,len); //写出到字节数组中}b1.flush();return b1.toByteArray();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}//字节数组写出到图片public static void Bytetofile(byte[] src,String filepath) {File dest = new File(filepath);InputStream in1 = null;OutputStream o1 = null;try {in1 = new ByteArrayInputStream(src);o1 = new FileOutputStream(dest);byte[] temp = new byte[5];int len = -1;while((len = in1.read(temp))!=-1) {o1.write(temp,0,len);}o1.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if(o1!=null) {o1.close();}} catch (IOException e) {e.printStackTrace();}}}}
注:某类型数据转为字节数组 除了字符串 其它的都是流的对接
装饰器模式
将一个对象嵌入到另一个对象中去,实际上相当于这个对象被另一个对象包装起来
public class Decorate2 {public static void main(String[] args) {coffee c1 = new coffee();System.out.println(c1.info()+c1.cost());suger s1 = new suger(c1);System.out.println(s1.info()+s1.cost());milk m1 = new milk(s1);System.out.println(m1.info()+m1.cost());}}//抽象组件:需要装饰的抽象对象(接口或抽象父类)interface drink{double cost(); //费用String info(); //说明}//具体组件:需要装饰的对象class coffee implements drink{private String name = " 原味咖啡 ";@Overridepublic double cost() {return 10;}@Overridepublic String info() {return name;}}//抽象装饰类:包含了对抽象组件的引用以及装饰者共有的方法abstract class decorate implements drink{private drink d1;public decorate(drink d) {this.d1 = d;}@Overridepublic double cost() {return this.d1.cost();}@Overridepublic String info() {return this.d1.info();}}//具体装饰类:被装饰的对象class milk extends decorate{public milk(drink drink) {super(drink);}@Overridepublic double cost() {return super.cost()*2;}@Overridepublic String info() {return super.info()+" 加入牛奶 ";}}class suger extends decorate{public suger(drink drink) {super(drink);}@Overridepublic double cost() {return super.cost()*2;}@Overridepublic String info() {return super.info()+"加入糖";}}
装饰流部分
**BufferedInputStream**和**BufferedOutputStream**这两个流是**缓冲字节流**,通过内部缓存数组来提高操作流的效率。 当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果**使用缓冲流就能够更高效的读写信息 **
BufferedInputStream/BufferedOutputStream
public class BufferedOutStream {public static void main(String[] args) {File f1 = new File("a.txt");FileOutputStream os1 = null;BufferedOutputStream bs1 = null;try {os1 = new FileOutputStream(f1);bs1 = new BufferedOutputStream(os1);String msg = "java2缓存流";byte[] temp = msg.getBytes();bs1.write(temp);bs1.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if(bs1!=null) { //释放外部流 内部字节流会自动释放bs1.close();}} catch (IOException e) {e.printStackTrace();}}}}
BufferedReader/BufferedWriter
BufferedReader/BufferedWriter字符缓存流增加了缓存机制,大大提高了读写文本文件的效率
readLine()方法是BufferedReader特有的方法,可以对文本文件进行更加方便的读取操作。
写入一行后使用newLine()方法换行。
public class BufferedT3 {public static void main(String[] args) {File f1 = new File("a.txt");Reader r1 = null;BufferedReader br1 = null;try {r1 = new FileReader(f1);br1 = new BufferedReader(r1);String str1 = null;while((str1=br1.readLine())!=null) { //readLine()方法实现一次读取一行操作System.out.println(str1);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if(br1!=null) {br1.close();}} catch (IOException e) {e.printStackTrace();}}}}
InputStreamReader/OutputStreamWriter 转换流
用来实现将字节流转化成字符流,并且能指定字符集(防止乱码)
//以字符流的形式操作字节流(纯文本)public class Convert1 {public static void main(String[] args) throws IOException {//用buffered建立缓冲 字节流转为字符流处理BufferedReader in1 = new BufferedReader(new InputStreamReader(System.in));BufferedWriter os1 = new BufferedWriter(new OutputStreamWriter(System.out));String msg = "";while(!msg.equals("exit")) {msg = in1.readLine();os1.write(msg);os1.newLine();os1.flush();}}}
//读写网络源码public class Prac {public static void main(String[] args) throws IOException{InputStream in1 = new URL("https://www.baidu.com/").openStream();//打开一个网络流BufferedReader br1 = new BufferedReader(new InputStreamReader(in1));FileOutputStream fo1 = new FileOutputStream("b1.html");BufferedWriter bw1 = new BufferedWriter(new OutputStreamWriter(fo1));String msg;while((msg=br1.readLine())!=null) {bw1.write(msg);bw1.newLine();}bw1.flush();}}
DataInputStream和DataOutputStream 数据流
提供了可以存取与机器无关的所有Java基础类型数据 方便后期不用强转数据类型
public class DataStream {public static void main(String[] args) throws IOException {//写出ByteArrayOutputStream b1 = new ByteArrayOutputStream();DataOutputStream d1 = new DataOutputStream(b1);//操作数据类型加数据d1.writeUTF("java学习");d1.writeInt(18);d1.writeBoolean(false);d1.writeChar('a');d1.flush();byte[] datas = b1.toByteArray();//读取ByteArrayInputStream b2 = new ByteArrayInputStream(datas);DataInputStream d2 = new DataInputStream(b2);//写入的顺序与写出要一致String msg = d2.readUTF();int a1 = d2.readInt();boolean b3 = d2.readBoolean();System.out.println(msg);}}
ObjectInputStream/ObjectOutputStream 对象流
以 “对象” 为数据源,但是必须将传输的对象进行序列化与反序列化操作
注:不是所有的对象都可以序列化 必须要实现一个Serializable接口 起标识作用
序列化
无论是何种类型的数据,都会以二进制序列的形式在网络上传送;
处理对象流的一种机制,即可以很方便的保存内存中java对象的状态,同时也为了方便传输
序列化:将java对象转化为字节序列的过程
反序列化:将字节序列转化为java对象的过程
对象序列化的作用有如下两种:
1. 持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中,比如:休眠的实现。以后服务器session管理,hibernate将对象持久化实现
2. 网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递
注:
1. static属性不参与序列化。
2. 对象中的某些属性如果不想被序列化,不能使用static,而是使用transient修饰
3. 为了防止读和写的序列化ID不一致,一般指定一个固定的序列化ID
ObjectOutputStream 对Java对象进行序列化处理,处理后的数据,不是文本数据,该数据保存到文件中(给系统看的),用文本编辑器打开是乱码。
public class ObjectStream1 {public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化ByteArrayOutputStream b1 = new ByteArrayOutputStream();ObjectOutputStream d1 = new ObjectOutputStream(new BufferedOutputStream(b1));//操作数据类型加数据employee emp1 = new employee("h",12312);d1.writeObject(emp1);d1.flush(); //每次写出都要强制刷新 避免后面找不到数据byte[] datas = b1.toByteArray();//对象数据还原 反序列化ByteArrayInputStream b2 = new ByteArrayInputStream(datas);ObjectInputStream d2 = new ObjectInputStream(new BufferedInputStream(b2));//写出的顺序与写入要一致Object o2 = d2.readObject();//添加类型转换避免类型转换错误 还原数据if(o2 instanceof employee) { //判断是否为其实例employee empobj =(employee)o2; //转为employee类型System.out.println(empobj.getName()+" "+empobj.getSalary());}}}//封装employee javabeanclass employee implements Serializable{private String name; //属性前加关键字transient,这个属性就不会被序列化private double salary;....}
PrintStream打印流
将OutputStream进行包装,可以方便地输出字符,更加灵活
//法一 PrintStreampublic class printstream {public static void main(String[] args) throws FileNotFoundException {PrintStream ps= System.out;ps.print("??");ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("print.txt")),true); //true表示自动刷新ps.println("abc");//ps.flush();//重定向输出端System.setOut(ps);System.out.println("学习");//重定向会控制台 通过系统定义好的FileDescriptor描述符System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true));ps.close();}}//法2 PrintWritepublic class PrintStream2 {public static void main(String[] args) throws FileNotFoundException {PrintWriter pw=new PrintWriter(new BufferedOutputStream(new FileOutputStream("print.txt")),true);pw.println("pw");pw.close();}}
Commons IO
Apache-commons工具包中提供了IOUtils/FileUtils,可以方便的对文件和目录进行操作
public class test1 {public static void main(String[] args) throws IOException {//文件大小long len = FileUtils.sizeOf(new File("src/RwArrayList/RwArrayList2.java"));//目录大小//len =FileUtils.sizeOf(new File("C:/C语言/eclipse"));System.out.println(len);//子孙级目录Collection<File> list3=FileUtils.listFiles(new File("C:/C语言/eclipse"),EmptyFileFilter.NOT_EMPTY, null);for(File temp:list3) {System.out.println(temp.getAbsolutePath());}Collection<File> list2=FileUtils.listFiles(new File("C:/C语言/eclipse"),EmptyFileFilter.NOT_EMPTY, DirectoryFileFilter.INSTANCE);for(File temp:list2) {System.out.println(temp.getAbsolutePath());}//读取文件String msg = FileUtils.readFileToString(new File("a.txt"),"UTF-8");System.out.println(msg);//读到字节数组中byte[] datas = FileUtils.readFileToByteArray(new File("a.txt"));System.out.println(datas.length);//逐行读取List<String> msgs=FileUtils.readLines(new File("a.txt"),"UTF-8");for(String temp:msgs) {System.out.println(temp);}//读取迭代器LineIterator lt = FileUtils.lineIterator(new File("a.txt"),"UTF-8");while(lt.hasNext()) {System.out.println(lt.nextLine());}//写出文件FileUtils.write(new File("t3.txt"), "沁园春","UTF-8",true); //true作为是否追加FileUtils.writeStringToFile(new File("t3.txt"), "沁园春","UTF-8",true);FileUtils.writeByteArrayToFile(new File("t3.txt"), "沁园春".getBytes("UTF-8"),true);//写出列表List<String> list4 = new ArrayList<String>();list4.add("H");list4.add("M");list4.add("N");FileUtils.writeLines(new File("t3.txt"), list4,true);}}
