1-IO流字符流
读取纯文本文件的内容用字符流
文件拷贝用字节流
1.1-组成
字节流+编码表
1.2-分类
FileWriter
(字符输出流)
字符输出流写出数据
输出流关联文件,文件不存在,自动创建
package com.lyl.writer;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符输出流
FileWriter fw = new FileWriter("day11\\a.txt");
//1.单个写出
fw.write(97);
//2.字符数组写出
char[] chars = {'b','c','d'};
fw.write(chars);
//3.写出数组一部分
fw.write(chars,1,1);
//4.写出字符串
fw.write("测试测试");
//5.写出字符串一部分
fw.write("我这句话还没写完呢",0,5);
//关流
fw.close();
}
}
输出结果:
练习:用字符流完成文件拷贝
package com.lyl.test;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest1 {
public static void main(String[] args) {
try (FileReader fr = new FileReader("day11\\a.txt");
FileWriter fw = new FileWriter("day11\\b.txt");) {
char[] chars = new char[1024];
int len;
while ((len = fr.read(chars)) != -1) {
fw.write(chars, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果:
注意:字符流拷贝只能拷贝纯文本文件!
建议:如果需求只是拷贝文件,一定要用字节流!!!
以上练习只是熟悉字符流的读写操作,拷贝还得是字节流
-
字符流写出数据,一定要关流,不然数据写不进去
-
不关流也可以用
flush
方法(刷新),flush
后可以继续写出数据,最后还得关流
flush
:将缓冲区(内置的小数组)的数据刷出到文件,刷出后可以继续调用write
方法写出数据
close
:其主要功能是关闭流释放资源,关闭之前会检查缓冲区是否还有数据,有的话,顺带进行刷出操作对
flush
现在的感触可能不是很深,但在之后的网络编程学习中会很有用
FileReader
(字符输入流)
1.3-字符缓冲流
缓冲流不具备读写操作,是用来包装输入输出流的
缓冲输入流:BufferedReader
缓冲输出流:BufferedWriter
特有方法
public String readLine();
:一次读取一整行字符串,没有读到数据则返回null
的结束标记
public void newLine()
:写出换行符,这个方法具有跨平台性
package com.lyl.buffered;
import java.io.*;
public class BufferedStream {
public static void main(String[] args) throws IOException {
//创建缓冲流对象
BufferedReader br = new BufferedReader(new FileReader("day11\\a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("day11\\b.txt"));
//line用来接受一整行数据
String line;
//将read读到的一整行字符串赋给line
while ((line = br.readLine()) != null) {
//写出字符串
bw.write(line);
//换行
bw.newLine();
}
//关流
br.close();
bw.close();
}
}
输出结果:
注意:如果要开启追加写入操作,应在
new FileWriter("day11\\b.txt")
参数中给出,例如:BufferedWriter bw = new BufferedWriter(new FileWriter("day11\\b.txt",true));
案例:文本排序
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
package com.lyl.test;
import java.io.*;
import java.util.TreeSet;
public class BufferedTest {
public static void main(String[] args) throws IOException {
//1.创建输入流对象,关联要读取的文件
BufferedReader br = new BufferedReader(new FileReader("day11\\出师表.txt"));
//2.创建TreeSet集合,准备存储读取到的每一行字符串(排序)
TreeSet<String> treeSet = new TreeSet<>();
//3.循环读取,将读取到的内容存入TreeSet集合
String line;
while ((line = br.readLine())!=null){
treeSet.add(line);
}
//4.关闭输入流
br.close();
//5,创建输出流对象,关联要写出的文件
BufferedWriter bw = new BufferedWriter(new FileWriter("day11\\出师表.txt"));
//6.遍历集合
for (String s : treeSet) {
//7.将集合中的数据写出到文件
bw.write(s);
bw.newLine();
}
//8.关闭输出流
bw.close();
}
}
输出结果:
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
9.今当远离,临表涕零,不知所言。
2-转换流
作用:1.将字节流转换为字符流进行使用(延后理解)
-
问题:为什么不直接创建字符流使用呢?
-
回答:今后有些流对象,不是我们自己创建,而是通过方法获取到的,返回的是字节流,而我想要按照字符流思想去使用,就需要用到转换流了
作用:2.可以按照指定的编码表,进行读写操作
场景:我要读取一个文件,这个文件的编码表是GBK码表,而平台默认读取方式,是按照UTF-8的形式去读取,为了避免乱码问题,就需要让程序按照GBK码表进行读取
2.1-分类
2.1.1-输入流:按照指定码表读取
InputstreamReader
前面学习的
FileReader
是它的子类,只能按平台的码表进行读取
package com.lyl.change;
import java.io.*;
public class ChangeStreamDemo {
public static void main(String[] args) throws IOException {
//缓冲流(字符流(转换流(字节流),编码表))
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\a.txt"),"GBK"));
System.out.println(br.readLine());
}
}
输出结果:
构造方法
InputStreamReader(InputStream in)
: 创建一个使用默认字符集的InputStreamReader
InputStreamReader(InputStream in, String charsetName)
: 创建一个使用指定命名字符集的InputStreamReader
2.1.2-输出流:按照指定码表写出
OutputstreamWriter
package com.lyl.change;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class ChangeStreamDemo2 {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\a.txt"),"GBK");
osw.write("你好哈哈哈哈");
osw.close();
}
}
输出结果:
构造方法
OutputStreamWriter(OutputStream out)
: 创建一个使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName)
:创建一个使用命名字符集的OutputStreamWriter
3-序列化流(对象流)
ObjectOutputstream
:写出对象
方法:
writeObject
ObjectInputStream
:读取对象
方法:
readObject
-
对象如果要被序列化,需要实现接口
Serializable
修改了对象所属的Javabean类 , 会抛出
InvalidClassException异常
解决 : 给对象所属的类加一个
serialVersionUID
private static final long serialVersionUID = ?L
-
实现好了接口之后,最好手动加入一个序列化版本号
private static final long serialVersionUID 1L;
-
给该成员变量加
transient
(瞬态) 关键字修饰,该关键字标记的成员变量不参与序列化过程(被隐藏) -
建议:写出数据只写一次,读取数据也只读取一次
package com.lyl.object_stream;
import com.lyl.domain.Student;
import java.io.*;
import java.util.ArrayList;
public class Demo1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObject();
readObject();
}
private static void readObject() throws IOException, ClassNotFoundException {
//创建对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day11\\stu.txt"));
//集合收取
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student stu : list) {
//打印
System.out.println(stu);
}
//关流
ois.close();
}
private static void writeObject() throws IOException {
//集合存储学生对象
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三",23));
list.add(new Student("李四",24));
list.add(new Student("王五",25));
//创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day11\\stu.txt"));
//写出对象
oos.writeObject(list);
//关流
oos.close();
}
}
输出结果:
Student{name = 张三, age = 23}
Student{name = 李四, age = 24}
Student{name = 王五, age = 25}
4-打印流
package com.lyl.test;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Scanner;
public class PrintStreamTest {
//886停止写入
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(System.in);
PrintStream ps = new PrintStream("day11\\test.txt");
while (true){
System.out.println("请输入:");
String msg = sc.nextLine();
if ("886".equals(msg)){
ps.close();
break;
}else {
ps.println(msg);
}
}
}
}
输出结果:
请输入:
123
请输入:
哈哈哈哈
请输入:
abc
请输入:
886
平时控制台打印输出,是调用
println
方法完成的这两个方法都来自于
java.io.PrintStream
类
-
优势:打印流可以自动刷新,自动换行
5-Properties-重点
介绍:java.util.Properties 继承于 Hashtable,来表示一个持久的属性集。
它使用键值结构存储数据,每个键及其对应值都是一个字符串。
HashMap 和 Hashtable 的区别
1. HashMap允许存储 null 键 null 值, Hashtable不行
2. HashMap线程不安全, Hashtable 线程安全
5.1-作为集合的使用(了解)
package com.lyl.prop;
import java.util.Enumeration;
import java.util.Properties;
public class PropertiesDemo {
/*
Properties作为集合的使用
*/
public static void main(String[] args) {
//创建Properties对象
Properties p = new Properties();
//setProperty方法添加数据
p.setProperty("username","admin");
p.setProperty("password","123456");
//获取集合中所有键(enumeration : 迭代器)
Enumeration<?> enumeration = p.propertyNames();
//循环判断是否还有下一个元素
while (enumeration.hasMoreElements()){
//获取元素(键)
Object o = enumeration.nextElement();
//打印 键+---+值
System.out.println(o+"---"+p.getProperty(o.toString()));
}
}
}
输出结果:
password---123456
username---admin
5.2-和IO相关方法
Properties
:用来加载配置文件
配置文件:程序中一些灵活多变的信息,放在了文件中存储
从流中加载数据到集合
package com.lyl.prop;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo2 {
public static void main(String[] args) throws IOException {
//1.创建空集合
Properties p = new Properties();
//2.创建输入流,关联要读取的文件
FileInputStream fis = new FileInputStream("day11\\config.properties");
//3.从流中加载数据(键值对)
p.load(fis);
fis.close();
//4.根据键找值(将配置文件中,键对对应的值取出来进行使用)(这一步操作最为重要,以后常用!)
String username = p.getProperty("username");
String password = p.getProperty("password");
System.out.println(username);
System.out.println(password);
}
}
输出结果:
admin
123456
将集合中的数据保存到流中
void store(OutputStream out,String comments)
:将此属性列表(键和元素对)写入此 Properties
表中,以适合于使用 load(InputStream)
方法的格式写入输出字节流
package com.lyl.prop;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
//创建空集合
Properties prop = new Properties();
//将数据塞进集合
prop.setProperty("username", "root");
prop.setProperty("password", "123456");
//创建输出流对象
FileOutputStream fos = new FileOutputStream("day11\\info.properties");
//集合调用store方法将数据写入流中
prop.store(fos, null);
//关闭流
fos.close();
}
}
输出结果:
更改null为其他值后:
//集合调用store方法将数据写入流中
prop.store(fos, "看看是什么");
注:并不是乱码,而是按照Unicode码表编码的中文汉字,properties配置文件对中文不支持,今后也不会向里面写中文,所以第二个参数即为注释,可写也可不写,不写就设置为null