Part01 :字符流
1、字节流的弊端:
当使用字节流读取中文,可能会出现乱码问题;
出现乱码问题的原因在于:文件中 中英文 字节数不同,可能读取中文读取一半;
2、字符编码表:
- ASCII码表,保存了(数字,字母,以及一些符号)对应的数字;每一个字符都是一个字节如:A-65、a-97、0-48
- GB2312码表(简体中文表),保存了常用的汉字(大约6000-7000个),一个中文占两个字节如:中-1111 1010 10101101
- GBK码表,保存了基本所有的汉字(大约20000多个),不管是英文中文还是符号,统统2个字节;
- Unicode:统一码表,不管是英文中文还是其他文字,符号,统统2个字节;
如:A-65-0000 0000 0100 0001 - UTF-8码表:在Unicode的基础上,做了一些优化:一个字节就可以存储的数据,不用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入编码信息;一个中文3个字节;
- ISO-8859-1:拉丁码表,服务器Tomcat中默认这个表;
3、编码和解码:
- 编码:把具体文字变成对应的码值
- 解码:把码值翻译成具体文字
4、字符流:
- 为了让程序员方便对字符流进行操作,Java提供了专门以字符作为操作单位的类—字符流;
- 字符流的底层仍然为字节流;
- 字符流只能操作字符,无法操作其它数据,如声音、视频等;
Part02 :转换流
1、OutputStreamWriter类:
-
OutputStreamWriter是一个字符流,extends Writer;
-
OutputStreamWriter是字符流通向字节流的桥梁 (编码)
-
构造:public OutputStreamWriter(OutputStream out);
//创建一个OutputStreamWriter对象 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("1.txt")); //写一个字符串 osw.write("你好"); //写一个字符串的一部分 osw.write("大帅比" ,1,2); //写一个字符 osw.write('h'); //写一个字符数组 char[] chars = {'f','h','r','l'}; osw.write(chars); //写一个字符数组的一部分 osw.write(chars,0,2); //关闭流 osw.close();
2、InputStreamReader类:
-
InputStreamReader是一个字符流,extends Reader;
-
InputStreamReader是字节流通向字符流的桥梁 (解码)
-
构造:public InputStreamReader(InputStream in);//默认查GBK码表
public InputStreamReader(InputStream in,String charsetName);//指定码表//创建InputStreamReader对象 InputStreamReader isr = new InputStreamReader(new FileInputStream("1.txt")); //创建InputStreamReader对象,指定编码为UTF-8 InputStreamReader isr1 = new InputStreamReader(new FileInputStream("1.txt"),"UTF-8"); //一次读一个字符数组 char[] chars = new char[4]; int b ; while ((b = isr.read(chars)) != -1){ System.out.println(b); System.out.println(chars); } //一次读一个字符 while ((b = isr1.read()) != -1){ System.out.println((char)b); } //关闭流 isr.close();
3、FileWriter和FileReader:
- 分别为OutputStreamWriter和InputStreamReader的子类
- FileWriter和FileReader不能指定编码表,默认编码表GBK
Part03 :序列化流和反序列化流
1、Serializable接口:
- 类通过实现Serializable接口以启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列号;
- Serializable接口中没有方法,可序列化标记
- 当写完一个对象之后,修改该对象所属的类,那么再次读取对象的时候,原来的类失效了,会抛出InvalidClassException(过期类)异常
⚠️JVM如何判断是否失效:当写完一个类时,内部有一个版本号,当修改这个类时,版本号发生变化;JVM通过判断版本号是否一致来判断类是否失效;当一个类实现了Serializable接口时,可以通过设置版本号serialVersionUID来使修改类之后该类不会过期;
public class Dog implements Serializable {
private static final long serialVersionUID = 1L;
int age;
String name;
public Dog(int age, String name) {
this.age = age;
this.name = name;
}
public Dog() {
}
@Override
public String toString() {
return "Dog{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
2、序列化流ObjectOutputStream:
-
对象的字节输出流,写对象到文件;
-
构造:public ObjectOutputStream(OutputStream out)
-
方法:punblic void writeObject(Object obj);//写一个对象,若这个对象未实现Serializable接口会抛出NotSerializableException异常;
//创建ObjectOutputStream对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt")); //写对象 Dog dog = new Dog(5,"旺财"); Dog dog1 = new Dog(2,"汪汪"); oos.writeObject(dog); oos.writeObject(dog1); //关闭流 oos.close();
3、反序列化流ObjectInputStream:
-
对象的字节输入流,从文件中读取读取对象
-
构造:public ObjectInputStream(InputStream In)
-
方法:public Object readObject( );//读一个对象
//创建ObjectInputStream对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt")); //读数据 Object obj = ois.readObject(); System.out.println(obj); //关闭流 ois.close();
4、transient关键字
- 用来修饰成员变量,但transient关键字修饰对成员变量无影响
- 在序列化时,被transient关键字修饰的成员变量在序列化时会被忽略
- 使用static关键字修饰的成员变量在序列化时也会被忽略
Part04 :打印流
1、打印流:打印数据
- PrintWriter:打印字符流,可以打印的目的地:字符串的文件名、File对象、其他OutputStream流、其他的Writer类
- PrintStream:打印字节流,可以打印的目的地:字符串的文件名、File对象、其他OutputStream流
注意⚠️:
- 这两个类方法一样;
- 区别在于:打印的目的地不同
Part05 :第三方框架commons-IO
1、使用第三方框架的步骤:
- 导入classpath:
- 在工程根目录下建立一个lib目录;
- 把要使用的jar包拷贝过来;
- 添加构建路径File–Project Structure–Modules–Dependencies–+
- 使用:和使用JDK提供的类一样
2、FileUtils类:
-
public static writeStringToFile(File file,String content);//将内容Content写入到file中
-
Public static String readFileToString(File file);//读取文件内容,返回String
-
public static copyFile(File srcFile,File destFile);//文件复制
-
public static copyDirectoryToDirectory(File srcDir,File destDir);//文件夹复制,可复制多级文件夹
FileUtils.writeStringToFile(new File("1.txt"),"很多事呢"); String s = FileUtils.readFileToString(new File("1.txt")); System.out.println(s); FileUtils.copyFile(new File("1.txt"),new File("2.txt")); FileUtils.copyDirectoryToDirectory(new File("/Users/feng/Desktop/原文件夹"),new File("/Users/feng/Desktop/目标文件夹"));