File(二)
文章目录
转换流
由于文件编码与代码文件编码不一致,从而会导致乱码,为了解决上述问题,可以使用转换流,在将数据输入和输出时指定流的编码格式与文件的编码格式保持一致。
字符输入转换流
字符输入转换流:InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流。
构造器 |
说明 |
public InputStreamReader(InputStream is ,String charset) | 可以把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码了 |
代码示例
package com.kc.system.io; import java.io.*; public class InputStreamReaderDemo01 { //代码UTF-8 public static void main(String[] args) throws Exception { InputStream is = new FileInputStream("./bbb.txt");//GBK // 把原始字节流转换成字符输入流 // Reader isr = new InputStreamReader(is); // 默认以UTF-8的方式转换成字符流。 还是会乱码的 跟直接使用FileReader是一样的 Reader isr = new InputStreamReader(is , "GBK"); // 以指定的GBK编码转换成字符输入流 完美的解决了乱码问题 BufferedReader br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null){ System.out.println(line); } } }
字符输出转换流
字符输入转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流。
构造器 | 说明 |
public OutputStreamWriter(OutputStream os,String charset) | 可以把原始的字节输出流按照指定编码转换成字符输出流(重点) |
代码示例
package com.kc.system.io; public class OutputStreamWriterDemo02 { public static void main(String[] args) throws Exception { // 1、定义一个字节输出流 OutputStream os = new FileOutputStream("./bbb.txt"); // 2、把原始的字节输出流转换成字符输出流 // Writer osw = new OutputStreamWriter(os); // 以默认的UTF-8写字符出去 跟直接写FileWriter一样 Writer osw = new OutputStreamWriter(os , "GBK"); // 指定GBK的方式写字符出去 // 3、把低级的字符输出流包装成高级的缓冲字符输出流。 BufferedWriter bw = new BufferedWriter(osw); bw.write("今天天气真好"); bw.write("今天天气真好"); bw.write("今天天气真好"); bw.close(); } }
打印流
打印流可以实现方便、高效的打印数据到文件中去。打印流一般是指:PrintStream,PrintWriter两个类。这两个类分类继承FilerOutStream,Writer。打印流可以看做是输出流的升级版。可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印boolean的true,写出去就是true,打印Hello World,写出去就是Hello World。
PrintStream构造器
构造器 | 说明 |
public PrintStream(OutputStream os) | 打印流直接通向字节输出流管道 |
public PrintStream(File f) | 打印流直接通向文件对象 |
public PrintStream(String filepath) | 打印流直接通向文件路径 |
方法
方法 | 说明 |
public void print(Xxx xx) | 打印任意类型的数据出去 |
PrintWriter构造器
构造器 | 说明 |
public PrintWriter(OutputStream os) | 打印流直接通向字节输出流管道 |
public PrintWriter (Writer w) | 打印流直接通向字符输出流管道 |
public PrintWriter (File f) | 打印流直接通向文件对象 |
public PrintWriter (String filepath) | 打印流直接通向文件路径 |
方法
方法 | 说明 |
public void print(Xxx xx) | 打印任意类型的数据出去 |
代码示例
package com.kc.system.io; import java.io.*; /** * PrintWriter 继承Writer * PrintStream 继承自FilerOutStream */ public class PrintDemo { public static void main(String[] args) throws FileNotFoundException { //可追加数据 // PrintStream ps= new PrintStream(new FileOutputStream("bbb.txt",true)); // ps.println("Hello World"); // ps.print("今天是10月25日"); // ps.close(); //PrintStream和PrintWriter的使用方式几乎一样 PrintWriter pw= new PrintWriter("bbb.txt"); pw.println("今天天气真好"); pw.println(12); pw.println(12.09); pw.println('a'); pw.println(true); pw.println(97); pw.close(); } }
输出语句重定向
重定向:可以将输出语句打印位置改为某个文件
代码示例
package com.kc.system.io; import java.io.FileNotFoundException; import java.io.PrintStream; /** * PrintStream 继承自FilerOutStream */ public class PrintDemo2 { public static void main(String[] args) throws FileNotFoundException { System.out.println("我为如来,又有何惧?"); System.out.println("相遇皆是缘缘尽莫强求。"); //重定向到bbb.txt文件 PrintStream ps = new PrintStream("bbb.txt"); //改变语句的重定向 System.setOut(ps); System.out.println("他宁愿死,也不肯输。"); System.out.println("如来是什么,如是道来。"); } }
上述重定向前
重定向后
序列化
对象序列化
序列化:以堆内存为基准,将生活在这上面的对象,通过某种的方式,以二进制的形式保存到硬盘上。
对象序列化API
使用对象字节输出流:ObjectOutStream
ObjectOutStream构造器
构造器 | 说明 |
public ObjectOutputStream(OutputStream out) | 把低级字节输出流包装成高级的对象字节输出流 |
ObjectOutStream方法
方法 | 说明 |
public final void writeObject(Object obj) | 把对象写出去到对象序列化流的文件中去 |
对象反序列化
反序列化:以堆内存为基准,将存放在硬盘上的对象数据还原对象。
反序列化
使用对象字节输入流:ObjectInputStream
ObjectInputStream构造方法
构造器 | 说明 |
public ObjectInputStream(InputStream out) | 把低级字节输如流包装成高级的对象字节输入流 |
反序列化的方法
方法 | 说明 |
public Object readObject() | 把存储到磁盘文件中去的对象数据恢复成内存中的对象返回 |
序列化ID
通常在序列化的时候会给类加上一个字段serialVersionUID,这个字段就是序列化ID
private static final long serialVersionUID = -4985775903060349049L;
序列化ID的作用
序列化ID是为了保证能够成功反序列化的成功,在进行反序列化的过程中,JVM会将来自输入流的当中的序列化ID和本地实体类的ID进行,若ID相同则说明保存在硬盘上的对象数据是该类所实例化的对象,反之则不能反序列化成功。如果在类中没有手动添加一个序列化ID,编译时会默认分配一个序列化ID,这样就会导致一个问题,那就是如果我们再次向类中添加字段时,重新编译就意味着重新分配一个序列化ID,假设没有添加字段前序列化后的对象数据为版本一,添加字段后,再次反序列化,此时由于实体类和序列化对象的ID不一致,就会导致序列化失败,为了解决上述问题可以一开始就手动添加一个类型为long的serialVersionUID,值保证不变,这种情况下,无论后序对类进行修改,编译时,总是使用自己手动加的,就不会出现反序列化失败了。
SerializeUtil
将上述序列化以及反序列化的方法封装成一个工具类,以便后续重复使用。
package com.kc.system.io; import java.io.*; public class SerializeUtil { //序列化,将对象转换成二进制 public static void saveObject(Object object) throws IOException { ObjectOutputStream oos = null; OutputStream out = null; try{ out = new FileOutputStream("D:/demo.txt"); oos = new ObjectOutputStream(out); oos.writeObject(object); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ out.close(); oos.close(); } } //反序列化,还原成对象 public static Object readObject() throws IOException { ObjectInputStream ois = null; InputStream is = null; try { is = new FileInputStream("D:/demo.txt"); ois = new ObjectInputStream(is); Object object = ois.readObject(); return object; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ is.close(); ois.close(); } return null; } }
Student
Studne类必须实现Serializable,Studnet才可以被序列化。Serializable一个空接口,可以将其视为可以序列化的标志。
package com.kc.system.io; import lombok.Data; import java.io.Serializable; @Data public class Student implements Serializable { private String name; private int age; private String address; private String school; }
对Studnet序列化和反序列化
package com.kc.system.io; import java.io.IOException; public class SerializeUtilDemo { public static void main(String[] args) throws IOException { Student s = new Student(); s.setName("叶秋涵"); s.setAge(18); s.setAddress("北海"); s.setSchool("哔哩哔哩"); SerializeUtil.saveObject(s); System.out.println("序列化完成了"); System.out.println("-----"); Student student = (Student)SerializeUtil.readObject(); System.out.println(student); } }
Student序列化结果
Studnent反序列化结果
向Student中添加weight字段
package com.kc.system.io; import lombok.Data; import java.io.Serializable; @Data public class Student implements Serializable { private String name; private int age; private String address; private String school; private double weight; }
再次反序化
package com.kc.system.io; import java.io.IOException; public class SerializeUtilDemo { public static void main(String[] args) throws IOException { Student student = (Student)SerializeUtil.readObject(); System.out.println(student); } }
控制台异常
java.io.InvalidClassException: com.kc.system.io.Student; local class incompatible: stream classdesc serialVersionUID = -2853823296530063815, local class serialVersionUID = 6312346039733332667//流中的ID与本地的类中ID不一致
解决异常
向类中添加serialVersionUID
private static final long serialVersionUID = -4985775903060349049L;
再次序列化覆盖上一个版本的对象数据,然后再反序列化
示例代码
package com.kc.system.io; import java.io.IOException; public class SerializeUtilDemo { public static void main(String[] args) throws IOException { Student s = new Student(); s.setName("叶秋涵"); s.setAge(18); s.setAddress("北海"); s.setSchool("哔哩哔哩"); SerializeUtil.saveObject(s); System.out.println("序列化完成了"); System.out.println("-----"); Student student = (Student)SerializeUtil.readObject(); System.out.println(student); } } //运行结果 //序列化完成了 //----- //Student(name=叶秋涵, age=18, address=北海, school=哔哩哔哩, weight=0.0)
再向Studnet中添加一个gender字段,在执行上述的代码就不会出异常了
properties
Properties是一个存储键值对数据的文件对象,该文件后缀为.properties。
首先创建一个user.properties,再向user.properties文件中添加是数据
package com.kc.system.io; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; public class PropertiesDemo1 { public static void main(String[] args) throws IOException { Properties properties = new Properties(); properties.setProperty("admin","123456"); properties.setProperty("name","叶秋涵"); properties.setProperty("pwassword","123456"); System.out.println(properties); properties.store(new FileWriter("./user.properties"),"用户信息");//该文件必须是存在的 } }
从user.properties获取数据
package com.kc.system.io; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Set; public class PropertiesDemo2 { public static void main(String[] args) throws IOException { //读取properties文件中的键值对信息 Properties properties = new Properties(); System.out.println(properties); //加载属性文件中的键值对数据到属性对象properties中去 properties.load(new FileReader("./user.properties")); System.out.println(properties); String name = properties.getProperty("name"); System.out.println(name); String admin = properties.getProperty("admin"); System.out.println(admin); String pwassword = properties.getProperty("pwassword"); System.out.println(pwassword); //获取配置文件中所有的键 Set<String> str = properties.stringPropertyNames(); for (String s : str) { System.out.print(s+" "); } } }
commons-io
commons-io是apache开源基金组织提供的一组有关IO操作的类库,就是对常见文件操作的封装,如文件的复制,删除,移动等。可以大的的提高效率。commons-io工具包提供了很多有关io操作的类。有两个主要的类FileUtils, IOUtils。
方法 | 说明 |
String readFileToString(File file, String encoding) | 读取文件中的数据, 返回字符串 |
void copyFile(File srcFile, File destFile) | 复制文件 |
void copyDirectoryToDirectory(File srcDir, File destDir) | 复制文件夹 |
maven依赖
commons-io commons-io 2.6
代码示例
package com.kc.system.io; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FileUtilsDemo { public static void main(String[] args) throws IOException { //完成文件的复制 IOUtils.copy(new FileInputStream("./bbb.txt"), new FileOutputStream("./bbb2.txt")); //完成文件复制到某个文件夹下 FileUtils.copyFileToDirectory(new File("D:/picture/1.jpg"),new File("D:/tools")); //完成文件夹复制到某个文件夹下 FileUtils.copyDirectoryToDirectory(new File("D:/picture"),new File("D:/tools")); //读取文件中的数据 String str = FileUtils.readFileToString(new File("./bbb.txt"),"UTF-8"); System.out.println(str); //复制文件 FileUtils.copyFile(new File("./bbb.txt"),new File("./bbb3.txt")); //删除文件夹 FileUtils.deleteDirectory(new File("D:/demo")); } }
最后的话
各位看官如果觉得文章写得不错,点赞评论关注走一波!谢谢啦!