1. 使用字符流来读写文本文件
**字符流:**可以处理能用Notepad++打开不乱码的文件。
字符输入流Reader -> InputStreamReader -> FileReader
构造:
FileReader(File file);
FileReader(String path);
InputStreamReader(InputStream is);
InputStreamReader(InputStream is,String charsetName); 可以指定字符集(字符编码)名称
关于字符编码/字符集的补充:
举例:当你用Notepad++存储一段内容时,到底在干什么?
当你输入了内容之后,它默认会以UTF-8进行解码,然后再通过UTF-8进行编码用于显示给你。
解码和编码的字符集必须保持一致,否则会出现乱码。
FileReader常用方法:
int read(char[] cha); 读取字符数据 将 数据读取到字符数组中 返回字符数
读取a.txt里面的内容(前提a.txt必须存在)
FileReader filereader=null;
try {
//1 创建对象 如果找不到a.txt会报错
filereader=new FileReader("d:\\a.txt");
//2 使用api读取信息
char[] chars=new char[1024];
// 将字符读取到字符数组中 并且返回读取字符数
// 文本文件(通过指定的字符集进行了编码显示的效果) -> 通过字节流读取 -> 以指定的字符集再进行编码
filereader.read(chars);
String str = new String(chars);
//写成1024是个习惯性问题 但是其实我们没有那么多字符 最后会有很多空格 所以需要去掉空格
System.out.println(str.trim());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
filereader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
此时控制台输出黑色倔犟
字符输出流Writer -> OutputStreamWriter -> FileWriter
构造:
FileWriter(File file);
FileWriter(String path);
OutputStreamWriter(OutputStream os);
OutputStreamWriter(OutputStream os,String chasetName); 可以将字节流转换为字符流
常用方法:
write(String str);
write(String str,int offset,int length);
write(char[] cha, int offset,int length);
把内容输出到a.txt中 这个a.txt不一定非要存在
FileWriter fw=null;
try {
//创建文件 只指定输出目的地
fw=new FileWriter("d:\\a.txt");
// fw.write("黑色heise");
//输出指定字符串 黑色
fw.write("黑色heise",0,2);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
进行一个文件的复制
FileReader fr=null;
FileWriter fw=null;
try {
//指定数据源
fr=new FileReader("d:\\a.txt");
//指定输出目的地
fw=new FileWriter("f:\\a.txt");
//字符输入流读取数据[边读边写]
char[] chars=new char[1024];
int len=0;
while((len=fr.read(chars))!=-1) {
// 4.字符输出流输出数据
fw.write(chars,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//关流
try {
fw.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
字节流:
字节输入流:InputStream -> FileInputStream
字节输出流:OutputStream -> FileOutputStream
2. 会使用高效缓冲流读写文本文件
高效缓冲字符流
输入流:BufferedReader
构造:
BufferedReader(Reader reader);
常用方法:
String readLine(); 读取一行
// 1.创建对象 最后一个可以不加分号
try(FileReader fr = new FileReader("d:/a.txt");
BufferedReader br = new BufferedReader(fr)){
// 2.读取一行
/*String readLine = br.readLine();
System.out.println(readLine);*/
String str = null;
while((str = br.readLine()) != null) {
System.out.println(str);
}
}catch (Exception e) {
e.printStackTrace();
}
-------------------------------------------------------------------
输出流:BufferedWriter
构造:
BufferedWriter(Writer writer);
常用方法:
write(String str);
writer(String str,int offset,int length);
write(char[] cha, int offset,int length);
因为有缓冲区,所以如果需要立即将内容输出到文本,需要调用flush()
方法刷新缓冲区。
关流也会刷新缓冲区。
FileWriter fw = null;
BufferedWriter bw = null;
try {
// 1.指定输出目的地
fw = new FileWriter("e:/a.txt");
bw = new BufferedWriter(fw);
// 2.和普通字符流方法相同
bw.write("haha");
// 刷新缓冲区 将内容输出 不再等待缓冲区满
bw.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
bw.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
FileReader fr = null;
BufferedReader br = null;
FileWriter fw = null;
BufferedWriter bw = null;
try {
fr = new FileReader("d:\\a.txt");
br = new BufferedReader(fr);
// 2.指定输出目的地
fw = new FileWriter("e:/pet.txt");
bw = new BufferedWriter(fw);
StringBuffer sb = new StringBuffer();
String str = null;
while ((str = br.readLine()) != null) {
sb.append(str);
}
System.out.println(sb);
String temStr = sb.toString();
// temStr = temStr.replace("{name}", "花花");
// temStr=temStr.replace("{type}", "阿拉斯加");
// temStr=temStr.replace("{master}", "黑色");
String afterStr = temStr.replace("{name}", "花花").replace("{type}", "阿拉斯加").replace("{master}", "黑色");
fw.write(afterStr);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {// 6.关流
try {
bw.close();
fw.close();
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
a.txt里面的内容:您好 我的名字是{name},我是一只{type},我的主人是{master}
3. 使用对象流实现序列化和反序列化
serializable
一个合格的JavaBean类应该有以下组成:
- 属性私有化
- 提供公共的getter/setter方法
- 提供无参构造
- 实现序列化接口
当Java在进行对象的序列化(对象一定实现过序列化接口)时,它会自动生成一个序列化版本ID(serialVersionUID),同理,在读取对象时(反序列化)时,Java还会再生成一个序列化版本ID。
java.io.InvalidClassException: cn.kgc.demo4.User; local class incompatible: stream classdesc serialVersionUID = -5990646266163102806, local class serialVersionUID = -3392451066535050577
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1883)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1749)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2040)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1571)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
at cn.kgc.demo4.Demo2.main(Demo2.java:19)
序列化
/**
* 输出对象 序列化:将内存中的Java对象以指定的二进制序列写入特定的流(二进制序列)
*
* 2019年3月3日 上午11:08:20
*/
public class Demo1 {
public static void main(String[] args) {
try (OutputStream os = new FileOutputStream("d:/object.txt");
ObjectOutputStream oos = new ObjectOutputStream(os);){
User user = new User();
user.setName("xxx");
user.setAge(12);
// 序列化
oos.writeObject(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出的是二进制 我们看不懂
反序列化
/**
* 读取对象:反序列化:将特定流中的数据重构为Java对象
* 2019年3月3日 上午11:11:41
*/
public class Demo2 {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("d:/object.txt");
ObjectInputStream ois = new ObjectInputStream(fis)){
// 反序列化
User user = (User) ois.readObject();
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 用户实体
* 2019年3月3日 上午11:07:29
*/
public class User implements Serializable {
/**
* 序列化ID
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
public User(){}
// 省略getter/setter
}