21.字符流和独特流
作者:互联网
@一贤不穿小鞋
1.所有字符流都是处理流封装字节流.
2.基本字符流
- 优点:可以设置读取和写入的编码.
2.1:基本字符输出流:Writer->OutputStreamWriter
eg:public static void main(String[] args) throws IOException {
//声明流对象
OutputStreamWriter osw=null;
try {
//1.创建流对象
osw=new OutputStreamWriter(new FileOutputStream("a1.txt",true), "utf-8");
//2.用流对象向文件中写入内容
osw.write("我是千锋人");
osw.append("我是中国人");
System.out.println("写入成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (osw!=null) {
osw.close();
}
}
}
2.2:基本字符输入流:Reader->InputStreamReader
eg:public static void main(String[] args) throws IOException {
//声明流对象
InputStreamReader osw=null;
try {
//1.创建流对象
osw=new InputStreamReader(new FileInputStream("a1.txt"), "utf-8");
//2.用流对象读取文件中内容
//准备一个字符数组
char[] c=new char[10];
//先读取一次,读取的内容存在数组中,返回的是读取的长度
int len;
//每读取一次就判断一次
while ((len=osw.read(c))!=-1) {
//将读取内容转换字符串并输出
String content=new String(c, 0, len);
System.out.println(content);
}
System.out.println("读取完毕");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (osw!=null) {
osw.close();
}
}
}
3.富二代字符流
- 优点:使用方便.
- 缺点:不能设置编译(如果读取的文件的编码与工作空间的编码不同时会出现乱码)
eg:public static void main(String[] args) {
//声明流对象
FileWriter fw=null;
FileReader fr=null;
try {
//1.创建流对象
fr=new FileReader("D:"+File.separator+"从前有座灵剑山.txt");
fw=new FileWriter("b1.txt");
//2.用流边读取边写入
//准备一个数组
char[] c=new char[100];
int len;
//每读取一次就判断一次
while ((len=fr.read(c))!=-1) {
//每读取一次,就将读取的内容写入到文件中
fw.write(c, 0, len);
}
System.out.println("拷贝成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
try {
if (fr!=null) {
fr.close();
}
if (fw!=null) {
fw.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4.字符缓冲流
- 优点:效率高;可一行一行读,写时可换行;可实现内容追加;可设置编码.
- 缺点:创建流麻烦.
eg:public static void main(String[] args) throws IOException {
//声明流对象
BufferedReader br=null;
BufferedWriter bw=null;
try {
//1.创建流对象
br=new BufferedReader(new InputStreamReader(new FileInputStream("D:"+File.separator+
"从前有座灵剑山.txt"), "utf-8"));
bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("c1.txt"), "utf-8"));
//2.用流边读取边写入,一行一行读,一行一行写入
String content;
while ((content=br.readLine())!=null) {
//每读取一行就写入一行
bw.write(content);
//换行
bw.newLine();
//刷新
bw.flush();
}
System.out.println("拷贝成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (br!=null) {
br.close();
}
if (bw!=null) {
bw.close();
}
}
}
总结:
1.打印流PrintStream(字节打印流,处理流),PrintWriter(字符打印流,处理流)
1.1:字节打印流的使用深入了解System.out.println()/print()/printf()/append()/write()
eg:public static void main(String[] args) {
//声明流对象
PrintStream ps1=null;
try {
//1.创建流对象
ps1=new PrintStream("d1.txt");
//2.用流向文件中写入内容
ps1.append("我爱千锋");
ps1.printf("%.2f", 3.123234344343);
ps1.println("我爱北京");
ps1.print("我爱中国");
ps1.write("哈哈".getBytes());
//注意:System.out得到就是PrintStream
System.out.println("写入成功");
System.out.append("1111");
System.out.write("dfefe".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (ps1!=null) {
ps1.close();
}
}
}
1.2:(扩展)输出重定向:给流重新定义一个方向输出.将原本在控制台输出的内容,转出到文件中.
eg: public static void main(String[] args) throws FileNotFoundException {
//输出重定向
System.setOut(new PrintStream("f1.txt"));
//将原本输出到控制台的内容,改变流的方向,输出到文件中
System.out.println("不忘初心");
System.out.println("方得始终");
}
1.3:(扩展)输入重定向:给流重新定义一个方向接收数据.将原来在控制台接收键盘录入的数据,现在在文件中接收这个数据.
eg:public static void main(String[] args) throws FileNotFoundException {
//输入重定向
System.setIn(new FileInputStream("f1.txt"));
Scanner input=new Scanner(System.in);
System.out.println("接收数据:");
String s1=input.next();
String s2=input.next();
System.out.println("接收的数据为:"+s1);
System.out.println("接收的数据为:"+s2);
}
2.对象流:
2.1:序列化:将Java程序(内存)中对象存在磁盘上文件中的过程.
- 持久化:将内存中短暂存储的数据长久的存在磁盘上.
- 反序列化:将磁盘上的文件中对象读取到Java程序(内存)中的过程.
2.2:对象输出流:ObjectOutputStream
- 用对象输出流向文件中写入对象的过程就是序列化过程.
- 注意:用对象流写入文件中的内容,不能直接查看文件(加密了),要用反序列化对象读取看.
eg:public static void main(String[] args) throws IOException {
//声明流对象
ObjectOutputStream oos=null;
try {
//1.创建流对象
oos=new ObjectOutputStream(new FileOutputStream("h1.txt"));
//2.第一种:用对象流调用方法向文件中写入一个String对象
//准备一个字符串对象
// String s1="我爱中国";
// oos.writeObject(s1);
//第二种:用对象流调用方法向文件中写入一个自定义的对象
// Student stu1=new Student("张三", 18,'男');
// oos.writeObject(stu1);
//第三种:用对象流存入多个对象:将多个对象存入集合中,再将集合整体序列化
Student stu1=new Student("张三1", 18,'男');
Student stu2=new Student("张三2", 28,'男');
Student stu3=new Student("张三3", 38,'男');
List<Student> stulist=new ArrayList();
stulist.add(stu1);
stulist.add(stu2);
stulist.add(stu3);
//将集合整体序列化
oos.writeObject(stulist);
System.out.println("写入成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (oos!=null) {
oos.close();
}
}
}
2.3:对象输入流:
- 用对象输入流读取文件中对象的过程就是反序列化过程.
eg:public static void main(String[] args) throws IOException {
//声明流对象
ObjectInputStream oos=null;
try {
//1.创建流对象
oos=new ObjectInputStream(new FileInputStream("h1.txt"));
//2.第一种:用对象流调用方法读取文件中String对象
// String s1=(String) oos.readObject();
// System.out.println("读取的内容为:"+s1);
//第二种:用对象流调用方法读取文件中写入一个自定义的对象
// Student stu1=(Student) oos.readObject();
// System.out.println("读取的内容为:"+stu1);
//第三种:将多个对象存入集合中,再将集合整体序列化,用对象流读取集合就可
List<Student> stulist=(List<Student>) oos.readObject();
for (Student s : stulist) {
System.out.println(s);
}
System.out.println("读取完毕");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (oos!=null) {
oos.close();
}
}
}
2.4:对象流在读写时注意
- 向文件中写入对象的方法与读取对象方法要匹配,否则会报EOFException异常.
- write数据类型()与read数据类型()要一致.
2.5:只有支持(实现)java.io.Serializable接口的对象才能写入对象流中.
2.6:问题
- 将一个自定义的类中对象用对象输出流存入到磁盘的文件中,再用对象输入流读取没有问题,如果将这个自定义类更改了,再用对象输入流读取会报stream classdesc serialVersionUID = 7084766393580739456, local class serialVersionUID = 3665876382104105971
- 原因:如果自定义的类只实现序列化接口,没有固定序列化版本号,那么这个自定义的类每更改一次,就会自动生成一个不同的序列化版本号.所以会导致你用一个版本号的 自定义类的对象去序列化,然后你用另一个版本号的自定义类去读取对象会版本号异常.
- 解决:将每个需要序列化的类实现序列化接口的同时,固定序列化版本号就不会出现问题了.
2.7:如果序列化类中某个属性不想被序列化,可以设置属性为static或transient.
2.8:用对象流序列化多个对象,将多个对象存入集合中,再将集合整体序列化.反序列化只需要读取一个集合.
3.Properties类:可以动态读取配置文件.
eg:public static void main(String[] args) throws FileNotFoundException, IOException {
//创建Properties对象
Properties p1=new Properties();
//用Properties对象调用方法动态加载配置文件
p1.load(new FileInputStream("jdbc.properties"));
//用Properties对象通过key得到value
System.out.println("用户名:"+p1.getProperty("username"));
System.out.println("密码:"+p1.getProperty("password"));
System.out.println("drivername:"+p1.getProperty("drivername"));
}
4.(扩展)装饰者模式:
- 作用:封装原有类,使其功能更强大.
- 要实现装饰者模式,注意以下几点内容:
a.装饰者类要实现真实类同样的接口 或继承同样父类.
b.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入)
c.装饰类对象在主类中接受请求,将请求发送给真实的对象(相当于已经将引用传递到了装饰类的真实对象)
d.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样的方法,装饰对象可以添 加一定操作在调用真实对象的方法,或者先调用真实对象的方法,再添加自己的方法)
标签:字符,读取,21,对象,序列化,System,new,out,独特 来源: https://blog.csdn.net/m0_53222768/article/details/117621373