前置知识:
序列化和反序列化
1.序列化就是在保存数据时, 保存数据的值和数据类型
2.反序列化就是在恢复数据时, 恢复数据的值和数据类型
3.需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该
类必须实现如下两个接口之一:
Serializable //这是一个标记接口,没有方法
Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口
节点流和处理流
节点流和处理流的区别和联系
1.节点流是底层流/低级流,直接跟数据源相接。
2.处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
3.处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]
处理流的功能主要体现在以下两个方面:
1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
2.操作的便捷:处理流可能提供了- -系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
常见的处理流BufferedReader和BufferedWriter
在关闭处理流时,只关闭外层流即可
一、字节流
字节流通常用来处理二进制文件,视频,音频,图片
1、inputStream
1.1、FileInputStream
/** * FileInputStream使用(文件-->程序) */ public class FileInputStream_ { public static void main(String[] args) { // readFile01(); readFile02(); } //单个字节的读取,效率比较低 public static void readFile01(){ String filePath="D://a.txt"; int readData=0; FileInputStream fileInputStream=null; try { //创建FileInputStream对象,用于读取 文件 fileInputStream = new FileInputStream(filePath); //一个字节一个字节的读,读取的数据存储在readData里,如果返回-1,则代表读取完毕 while ((readData = fileInputStream.read())!=-1){ System.out.print((char) readData);//转成char输出 } } catch (IOException e) { e.printStackTrace(); }finally { //关闭文件流释放资源 try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } public static void readFile02(){ String filePath="D://a.txt"; int readLen=0; FileInputStream fileInputStream=null; //添加一个Byte容量设置为10数组 byte[] bytes = new byte[9]; try { //创建FileInputStream对象,用于读取文件 fileInputStream = new FileInputStream(filePath); //从该输入流读取最多10个字节的数据到字节数组。 //如果返回-1,则代表读取完毕 //如果读取正常返回实际读取的字节数 while ((readLen=fileInputStream.read(bytes))!=-1){ System.out.print(new String(bytes,0,readLen)); } } catch (IOException e) { e.printStackTrace(); }finally { //关闭文件流释放资源 try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1.2、ObjectInputStream(对象反序列化)
注意先进行 ObjectOutputStream 序列化到 D:\a.dat 文件中 然后才进行的反序列化
public class ObjectInputStream_ { public static void main(String[] args) throws IOException, ClassNotFoundException { //指定反序列化的文件 String filePath="D:\\a.dat"; ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath)); //读取 //反序列的顺序需要和保存的数据的顺序一致,否则会出现异常 System.out.println(objectInputStream.readInt()); System.out.println(objectInputStream.readBoolean()); System.out.println(objectInputStream.readChar()); System.out.println(objectInputStream.readDouble()); System.out.println(objectInputStream.readUTF()); Object dog = objectInputStream.readObject(); System.out.println("运行类型:"+dog.getClass()); System.out.println("dog信息:"+dog);//底层 Object-->Dog //关闭外层流即可 objectInputStream.close(); } }
可以看到输出:
2、OutputStream
2.1、FileOutputStream
public class FileOutputStream_ { public static void main(String[] args) { writeFile(); } /** * 使用FileOutputStream将数据写入文件中 * 如果数据不存在,则自动创建该文件 */ public static void writeFile(){ String filePath="D:\\a.txt"; FileOutputStream fileOutputStream=null; try { //得到FileOutputStream对象 //1、这种创建方式,写入的内容是覆盖原来的文件中的内容 //2、在构造器中添加 true 为追加填写 fileOutputStream = new FileOutputStream(filePath,true); //写入一个字节 // fileOutputStream.write('a'); fileOutputStream.write(97); //写入字符串 str.getBytes()字符串转为字节数组 String str="hollow"; //fileOutputStream.write(str.getBytes()); //也可以指定字节数组中的起始位置,末尾位置 fileOutputStream.write(str.getBytes(),0,str.length()); } catch (IOException e) { e.printStackTrace(); }finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
2.2、ObjectOutputStream(对象序列化)
/** * ObjectOutputStream的使用,完成数据的序列化 */ public class ObjectOutputStream_ { public static void main(String[] args) throws Exception { //序列化后,保存的格式,不是纯文本,而是按照他的格式来保存 String filePath = "D:\\a.dat"; ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath)); //序列化数据到 D:\a.bat objectOutputStream.write(100);//int-->Integer(实现了Serializable) objectOutputStream.writeBoolean(true);//boolean-->Boolean(实现了Serializable) objectOutputStream.writeChar('a');//chat-->Character(实现了Serializable) objectOutputStream.writeDouble(1.1);//double-->Double(实现了Serializable) objectOutputStream.writeUTF("阿龙学习");//String //保存一个对象 objectOutputStream.writeObject(new Dog("旺财",5)); objectOutputStream.close(); System.out.println("序列化数据保存完毕"); } } //lombok插件 @Data @AllArgsConstructor @NoArgsConstructor //要实现Serializable接口才能够进行序列化 class Dog implements Serializable { private String name; private int age; }
2.3、PrintStream(字节打印流)
/** * PrintStream字节打印流 */ public class PrintStream_ { public static void main(String[] args) throws IOException { // System.out 就是 PrintStream PrintStream out = System.out; //在默认情况下,默认打印的是标准输出(即 显示器) out.println("你好"); //因为底层使用的是write,所以可以直接调用write进行打印/输出 out.write("hello,你好!".getBytes(StandardCharsets.UTF_8)); //关闭流。 out.close(); //我们可以修改打印输出流的位置/设备 //修改成"D:\\a.txt" //这句话将会输出到D:\a.txt System.setOut(new PrintStream("D:\\a.txt")); System.out.println("这句话将会输出到D:\\a.txt"); } }
二、字符流
通常用来处理文本文件,更高效。
1、Reader
1.1、FileReader
public class FileReader_ { public static void main(String[] args) { String filePath="d:\\a.txt"; FileReader fileReader=null; int data= 0; char[] chars = new char[10]; //1、创建FileReader对象 try { fileReader = new FileReader(filePath); //循环读取,使用read(chars),返回的是实际读取到的字符数 //如果返回-1则表示读到文件结尾 while ((data = fileReader.read(chars))!=-1){ System.out.print(new String(chars,0,data)); } } catch (IOException e) { e.printStackTrace(); }finally { try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1.2、BufferedReader
BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader子类 (BufferedWriter也是一样的操作)
public class BufferedReader_ { public static void main(String[] args) throws Exception { //异常也可以try catch String filePath = "D:\\a.txt"; //创建bufferedReader BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath)); //读取 String line;//按行读取,效率高 //1.bufferedReader.readLine() 按行读取文件 //2.当返回为空时,表示文件读取完毕。 while ((line = bufferedReader.readLine())!=null){ System.out.println(line); } //关闭流,只需要关闭外层的流,即bufferedReader,因为底层会自动的去关闭节点流 FileReader bufferedReader.close(); } }
1.3、InputStreamReader(转换流,并可以指定编码格式读取)
/** * InputStreamReader 转换流解决中文乱码问题 * 将字节流 FileInputStream 转换成字符流 InputStreamReader, 指定编码 gbk/utf-8 */ public class InputStreamReader_ { public static void main(String[] args) throws IOException { String filePath = "D:\\a.txt"; //把 new FileInputStream(filePath) 转成 InputStreamReader 同时指定了编码 utf-8 InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8); //把 InputStreamReader 传入 BufferedReader BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String readLine; while(( readLine = bufferedReader.readLine())!=null){ System.out.println(readLine); } bufferedReader.close(); } }
2、Writer
2.1、FileWriter
注意:FileWriter使用后,必须要关闭(close)或刷新(flush)流, 否则写入不到指定的文件!
public class FileWriter_ { public static void main(String[] args) { String filePath="D:\\a.txt"; FileWriter fileWriter=null; String str="哈哈哈哈哈哈哈哈哈"; try { fileWriter = new FileWriter(filePath,true);//true为追加,不写则覆盖 //fileWriter.write(str); fileWriter.write(str,0,2);//指定str的某一部分 } catch (IOException e) { e.printStackTrace(); }finally { try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } }
2.2、BufferedWriter
public class BufferedWriter_ { public static void main(String[] args) throws IOException { String filePath="D:\\a.txt"; //创建BufferedWriter BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));//追加要在节点流中进行设置 bufferedWriter.write("红红火火恍恍惚惚红红火火恍恍惚惚吼吼吼1"); //插入一个换行 bufferedWriter.newLine(); bufferedWriter.write("红红火火恍恍惚惚红红火火恍恍惚惚吼吼吼2"); //插入一个换行 bufferedWriter.newLine(); bufferedWriter.write("红红火火恍恍惚惚红红火火恍恍惚惚吼吼吼3"); //关闭外层流即可 bufferedWriter.close(); } }
2.3、OutputStreamWriter(转换流,并可以指定编码格式写入)
/** * 将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter, * 对文件进行写入(按照gbk格式,可以指定其他,比如utf-8/utf8) */ public class InputStreamWriter_ { public static void main(String[] args) throws IOException {//异常直接进行的抛出,也可以try catch String filePath = "D:\\a.txt"; OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), "gbk"); outputStreamWriter.write("gbk格式的编码"); //关闭流 outputStreamWriter.close(); } }
2.4、PrintWriter(字符打印流)
public class PrintWriter_ { public static void main(String[] args) throws IOException { //创建PrintWriter对象 PrintWriter printWriter = new PrintWriter(new FileWriter("D:\\a.txt")); //将会打印到 D:\a.txt printWriter.println("哈喽你好 "); printWriter.close(); //flush + 关闭流 } }
三、Properties类
load:加载配置文件的键值对到Properties对象
list:将数据显示到指定设备
getProperty(key):根据键获取值
setProperty(key,value):设置键值对到Properties对象
store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果
含有中文,会存储为unicode码
1、Properties读取数据
public class Properties_read { public static void main(String[] args) throws IOException { //使用Properties读取ycl.properties文件 Properties properties = new Properties(); //加载指定的配置文件 properties.load(new FileReader("src/main/resources/ycl.properties")); //键值对显示到控制台 properties.list(System.out); //根据key 获取对应的值 String id = properties.getProperty("id"); System.out.println("id是:"+id); } }
2、Properties写入数据
public class Properties_writer { public static void main(String[] args) throws IOException { //使用Properties类, 创建配置文件,修改配置文件内容 Properties properties = new Properties(); //设置内容
//如果该文件没有对应的key,就是创建
//如果该文件有对应的key,就是修改 properties.setProperty("charset","utf-8"); properties.setProperty("username","小刚");//中文保存的是unicode码 properties.setProperty("pwd","123567894"); //将k-v 存储至文件 properties.store(new FileOutputStream("D:\\a.data"),null); System.out.println("保存成功"); } }
四、copy练习
1、字节流copy练习
public class FileCopy { public static void main(String[] args) { copy(); } public static void copy(){ String resourcePath="D:\\壁纸\\1.jpg"; String targetPath="D:\\壁纸\\3.jpg"; FileInputStream fileInputStream=null; FileOutputStream fileOutputStream=null; int readLen=0; try { fileInputStream = new FileInputStream(resourcePath); fileOutputStream=new FileOutputStream(targetPath); //定义一个数组提高效率 byte[] bytes = new byte[1024]; while ((readLen=fileInputStream.read(bytes))!=-1){ //边读边写 fileOutputStream.write(bytes,0,readLen);//必须用这个参数,否则出现文件损失 } System.out.println("copy完成"); } catch (IOException e) { e.printStackTrace(); }finally { try { fileInputStream.close(); fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
2、缓冲字符流copy文本练习
BufferedReader和BufferedWriter 是按照字符操作的,不要去操作二进制文件(声音、视频、doc、pdf、图片等等),拷贝后的文件可能会造成文件损坏
public class Buffered_copy { public static void main(String[] args) { //源文件路径 String resourcePath = "D:\\a.txt"; //目标文件的路径 String targetPath = "D:\\b.txt"; BufferedReader bufferedReader = null; BufferedWriter bufferedWriter = null; try { //创建bufferedReader、bufferedWriter bufferedReader = new BufferedReader(new FileReader(resourcePath)); bufferedWriter = new BufferedWriter(new FileWriter(targetPath,true));//true表示追加写入 String line; //readLine() 读取一行内容,但是没有换行 while ((line = bufferedReader.readLine()) != null) { //每读取一行就写入 bufferedWriter.write(line); //插入换行 bufferedWriter.newLine(); } } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭流 if (bufferedReader!=null){ bufferedReader.close(); } if (bufferedWriter!=null){ bufferedWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
3、缓冲字节流copy二进制文件(copy文本文件一样可以)
/** * BufferedInputStream、BufferedOutputStream的使用 */ public class Buffered_copy02 { public static void main(String[] args) { String resourcePath = "D:\\壁纸\\2.jpg"; String targetPath = "D:\\壁纸\\4.jpg"; BufferedInputStream bufferedInputStream = null; BufferedOutputStream bufferedOutputStream = null; try { //创建对象 bufferedInputStream = new BufferedInputStream(new FileInputStream(resourcePath)); bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(targetPath)); int readLen; byte[] buf = new byte[1024]; //返回读取到的长度,当返回-1时,就表示文件读取完毕 while ((readLen = bufferedInputStream.read(buf))!=-1){ bufferedOutputStream.write(buf,0,readLen); } } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭外层处理流即可,底层会自动关闭节点流 if (bufferedInputStream != null) { bufferedInputStream.close(); } if (bufferedOutputStream!=null){ bufferedOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } }