1.IO流
1. 为什么学IO?
我们之前学的容器存储数据都是一个临时存储,程序一停,容器中的数据就不存在了
1.造成的问题:当程序结束之后,我们还想要存储的数据,就不可能了
2.考虑的问题:能不能想办法将数据永久保存起来
3.怎么永久保存:将数据保存到硬盘上
4.我们用什么样的技术去实现将数据保存到硬盘上呢?->IO流实现
2.什么是IO技术:
一种将数据保存到硬盘上,还可以从硬盘上读取数据,或者一个设备上的数据传输到另外一个设备的技术
I:Input->输入
O:Output->输出
3.IO流的分类
字节流的两个顶层父类:
InputStream : 字节输入流
OutputStream :字节输出流
总结:他们都是抽象类,所以不能直接创建对象想要创建对象的话需要使用它们的子类,FileInputStream FileOutputStream
字符流的两个顶层父类:
Reader :字符输入流
Writer:字符输出流
总结:他们都是抽象类,所以不能直接创建对象想要创建对象的话需要使用它们的子类,FileReader FileWriter
这些体系的子类都以父类名作为后缀名
而且子类名的前缀就是该对象的功能
字符流缓冲区:
BufferedWrite
newLine():换行
BufferedReader
readLine(): 使用了读取缓冲区的read()将读取到的字符进行缓冲并判断换行的标记,将标记前的缓存数据变成字符串返回
bufr.read():这个read是从缓冲区中取出字符数据,所以覆盖了父类中的read方法
缓冲的原理:
其实就是从源中获取一批数据装进缓冲区中,再从缓冲区中不断的取出一个一个的数据在此次取完后再从源中继续读取一批数据进缓冲区,当
源中的数据取光是,用-1作为结束标记
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道使用哪一个对象合适,想要知道开发时用到哪些对象,只要通过四个明确即可
1.明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2.明确数据是否是纯文本数据
源:
是纯文本:Reader
不是纯文本:InputStream
目的:
是纯文本:Writer
不是纯文本:OutputStream
到这里就可以明确使用需求中具体要使用那个体系
3.明确具体设备
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4.是否需要其他额外功能
(1)是否需要高效(缓冲区):
是就加缓冲区 Buffer
(2)转换
4.通用写法
a.创建流对象(输入流,输出流)
b.写数据或读数据(write(),read())
c.关流close() 原则为:先开的后关
//-----------------------------------使用输出输入流完成文件复制----------------------
//创建流对象
FileInputStream fis=new FileInputStream("D:\\idea\\io\\image\\5.ipg");
FileOutputStream fos=new FileOutputStream("D:\\idea\\io\\image\\6.ipg");
//进行读取,创建一个字节数组,然后进行循环读取
byte[] bytes=new byte[1024];
//定义一个变量,原因为,为了记录是否读完,read()方法读完返回-1
int len=0;
while((len=fis.read(bytes)!=-1){
//边读边写,len是读到的位置,一次写一个字节数组的一部分
fos.write(bytes,0,len);
}
//关流
fos.close();
fis.close();
5.标准的异常处理
//创建一个空的输出流对象
FileOutputStream fos=null;
try{
//为输出流赋值
fos=new FileOutputStream("day\\a.txt");
fos.write(97);
}catch(Exception e){
e.printStarkTrace();
}finally{
try{
//判断是否创建成功,成功的话就关流
if(fos!=null){
fos.close();
}catch(IOException e){
e.printStarkTrace();
}
}
}
6.properties集合(属性集)
格式为:key=value key和value都是String类型,不要双引号,写完键值后需要换行
1.构造方法:
Properties pro=new Properties()
2.向集合中存储键值对(相当于一种Map集合的一种)
总结:
这个集合经常与流在一起使用,他的获取键和值与Map集合形似,有keySet和entry
public class PropertiesDemo {
public static void main(String[] args) throws Exception{
FileReader fr = new FileReader("module\\ps.Properties");
// FileWriter fw = new FileWriter("module\\ps.Properties");
Properties ps = new Properties();
ps.load(fr);
Set<String> strings = ps.stringPropertyNames();
for (String string : strings) {
String s= ps.getProperty(string);
System.out.println(s);
}
ps.setProperty("z","12");
}
}
7.其它流
1.转换流
InputStream:字节流通向字符流的桥梁
构造:
InputStream(InputStream in,String charsetName)
charsetName:文件的编码,IDEA的默认编码为utf-8
OutputStream:字符流通向字节流的桥梁
构造:
OutputStream (OutputStream os,String charsetName)
charsetName:文件的编码,IDEA的默认编码为utf-8
2.序列化流
1.序列化:ObjectOutputStream
对象需要实现Serializable接口
序列化也就是往文件中写对象
ObjectOutputStream(OutputStream out)
写对象的方法为writeObject(对象)
2.反序列化:ObjectInputStream
ObjectInputStream---->读对象
方法:readObject
注意事项:以为对象默认类型为Object,在使用的自己的类型时需要强转
不想被反序列化操作:
1.将成员变量定义成static
2.瞬态关键字:transient
注:以引发的问题,在序列化后,修改代码没有重新序列化之后直接反序列化
解决方案:
在实体类上加:public static final long serialversionUID=42L;
3.打印流
public PrintStream(String fileName):使用指定的文件创建一个新的打印流
set(ps):打印到指定的文件
ps为是将数据打印到这个ps文件中,ps就是个文件名
8.装饰者模式
1.装饰类和被装饰类,必须实现相同的接口
2.在装饰类中必须传入被装饰类的引用
3.在装饰类中对需要扩展的方法进行扩展
4.在装饰类中对不需要扩展的方法调用被装饰类中的同名方法
2.Commons-io工具包
导入jar包:
1.在module下创建文件夹lib
2.将jar包文件复制到lib下面
3.lib文件夹右键选择add as library
4.level选项,选择module
1.IOUtils类
提供的方法为静态的:
IOUtils.copy(InputStream in,OutputStream out)
IOUtils.closeQuietly(任意流对象) 自动处理close()方法,,抛出异常
2.FileUtils类
FileUtils.copyDirectoryToDirectory(File str,File dest) :参数为File类型
writerStringToFile(File file,String str) :将字符串写到文档中
readFileToString(File file) :读取文本文档文件,返回字符串