节点流和处理流的区别和联系:
- 节点流是底层流/低级流,直接和数据源相连
- 处理流(包装流) 包装节点流,即可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
- 处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源项链
处理流的功能主要体现在以下两个方面:
- 性能的提高:主要以增加缓冲的方式来提高输入输出的效率
- 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
修饰器设计模式:
有一个超类,有多个子类,功能类中又有一个超类属性,这样功能类就可以使用多种子类的方法实现。并且对他们进行二次开发。
BufferedReader
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("e:\\program.txt"));
String line;//按行读取
while ((line=bufferedReader.readLine())!=null){//当返回null时,表示读取结束
System.out.println(line);
}
//注意:这里只需要关闭bufferedReader就可以了,因为底层会自动关闭节点流
bufferedReader.close();
}
BufferedWriter
public static void main(String[] args) throws IOException {
final FileWriter fileWriter = new FileWriter("e:\\bufferedWriterTest.txt");
fileWriter.write("hello,BufferedWriterTest0");
BufferedWriter bufferedWriter=new BufferedWriter(fileWriter);
bufferedWriter.write("\n");//手动进行换行
bufferedWriter.newLine();//根据系统不同自动输入\r或\n进行换行
bufferedWriter.write("hello,BufferedWriterTest1");
bufferedWriter.newLine();
bufferedWriter.write("hello,BufferedWriterTest2");
bufferedWriter.write("hello,BufferedWriterTest3");
bufferedWriter.close();//关闭处理流(包装流),底层会自动关闭节点流
}
BufferedCopy
public static void main(String[] args) {
BufferedWriter bufferedWriter=null;
BufferedReader bufferedReader=null;
String srcFilePath="e:\\program.txt";
String destFilePath="e:\\program2.txt";
try {
bufferedReader=new BufferedReader(new FileReader(srcFilePath));
bufferedWriter=new BufferedWriter(new FileWriter(destFilePath,true));
String line;//BufferedRead的readLine方法会返回String类型结果
while ((line=bufferedReader.readLine())!=null){
bufferedWriter.write(line);
bufferedWriter.newLine();//readLine不会读取换行符,需要手动换行
}
}catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader!=null){
bufferedReader.close();
}
if (bufferedWriter!=null){
bufferedWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BUfferedCopy:
public static void main(String[] args) {
String srcFilePath="E:\\ZZU_CSP2021Demo\\ZZU_CSP2021Demo.zip";
String destFilePath="e:\\test.zip";
BufferedInputStream bufferedInputStream= null;
BufferedOutputStream bufferedOutputStream=null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFilePath));
bufferedOutputStream=new BufferedOutputStream(new FileOutputStream(destFilePath,true));
byte[] buf=new byte[1024];
int readLen=0;
while ((readLen=bufferedInputStream.read(buf))!=-1){
bufferedOutputStream.write(buf,0,readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedInputStream!=null){
bufferedInputStream.close();
}
if (bufferedOutputStream!=null){
bufferedOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象流
将int=100 保存到文件中,注意不是100数字,而是int 100,并且能够从文件中直接恢复int 100
将Dog dog=new Dog(“小狗”,5);保存到文件中,并且能够从文件中直接恢复dog对象。
序列化和反序列化:
- 序列化就是在保存数据时,保存数据的值和数据类型
- 反序列化就是在恢复数据时,恢复数据的值和数据类型
- 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
- Serializable //这是一个标记接口
- Externalizable 这个接口有方法需要实现,一般不使用
Serializable接口源码:
public interface Serializable {
}
没有任何方法,是一个标记接口
ObjectOutputStream
public class ObjectOutputStream_ {
public static void main(String[] args) throws Exception {
//序列化后保存的并不是一个纯文本文件,而是一个.dat文件
String filePath="e:\\object.dat";
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeInt(100);//int会自动转换成Integer Integer实现了Serializable接口
objectOutputStream.writeBoolean(true);
objectOutputStream.writeDouble(8.88);
objectOutputStream.writeChar('a');//char->Character Character实现了Serializable接口
objectOutputStream.writeUTF("用ObjectOutputStream保存String");//String实现了Serializable接口
objectOutputStream.writeObject(new Dog("秋田狗",5));//保存的对象类必须实现了Serializable接口
System.out.println("保存成功");
objectOutputStream.close();
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
ObjectInputStream
- 反序列化取数据时顺序需要与序列化时一致
- 当序列化的类发生变化时,需要重新序列化,否则会报错
- dog的编译类型是Object,dog的运行类型是Dog
- 如果需要调用dog类的方法,需要将dog向下转型为Dog类型
public static void main(String[] args) throws IOException, ClassNotFoundException {
String filePath="e:\\object.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
//读取顺序要与序列化顺序保持一致
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readDouble());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readUTF());
//dog的编译类型是Object,dog的运行类型是Dog
Object dog = objectInputStream.readObject();
System.out.println("运行类型= "+dog.getClass());
System.out.println("dog信息="+dog);
objectInputStream.close();
}
对象流注意事项
- 读写顺序要一致
- 要求实现序列化或反序列化的对象,类都要实现Serializable接口
- 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
- 序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的对象
- 序列化对象时,要求里面属性的类型也需要实现序列化接口
- 序列化具有可继承性
标准输入输出流
System.in 默认设备 键盘
编译类型InputStream
运行类型BufferedInputStream
System.out 默认设备 显示器
编译类型 PrintStream
编译类型 PrintStream
public static void main(String[] args) {
System.out.println(System.in);//编译类型为InputStream 运行类型为BufferedInputStream
System.out.println(System.out);//编译类型为PrintStream 运行类型为PrintStream
String text;
Scanner scanner=new Scanner(System.in);
System.out.println("请输入:");
System.out.println(scanner.next());
}
修改标准输出流的输出位置:
System.setOut(new PrintStream("e:\\f1.txt"));
System.out.println("输出到e:\\f1.txt了");
转换流
默认为UTF-8,当编码不为UTF-8时,会出现乱码,此时需要使用转换流InputStreamReader(Reader的子类,可以将InputStream(字节流)包装成Reader(字符流))
OutputStreamReader(Writer的子类,可以将OutputStream包装成Writer(字符流))
可以在使用时指定编码格式(比如UTF-8,gbk,gb2312,ISO8859-1等)
public static void main(String[] args) throws IOException {
//使用BufferedReader,当文件编码不是utf-8时,出现了乱码
//BufferedReader bufferedReader = new BufferedReader(new FileReader("e:\\codequestion.txt"));
//String line = bufferedReader.readLine();
//System.out.println(line);
//bufferedReader.close();
//将字节流FileInputStream转换成字符流InputStreamReader
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("e:\\codequestion.txt"), "gbk");
BufferedReader bufferedReader1 = new BufferedReader(inputStreamReader);
String readLine = bufferedReader1.readLine();
System.out.println(readLine);
bufferedReader1.close();
}
public static void main(String[] args) throws IOException {
String charset="gbk";
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("e:\\OutputStreamWriter.txt"), charset);
outputStreamWriter.write("这是一个编码类型为gbk的文件");
System.out.println("编码类型为 "+charset+"的文件");
outputStreamWriter.close();
}
Properties类
有一个配置文件mysql.properties
ip=192.168.xx.xx
name=xxx
password=xxx
使用Properties类可以方便地解决
-
Properties是专门用于读取配置文件的集合类
配置文件的格式:
键=值
键=值
-
注意:键值对不需要有空格,值不需要用引号引起来。默认类型为String
-
常用方法:
- load :加载配置文件的键值对到Properties对象
- list :将数据显示到指定设备
- getProperty(key):根据键获取值
- setProperty(key,value):设置键值对到Properties对象
- store:将Propertie中的键值对存储到配置文件中,在idea中,保存信息到配置文件,如果含有中文,会存储为Unicode码
public static void main(String[] args) throws IOException {
//使用String类的split方法取得键和值
BufferedReader br = new BufferedReader(new FileReader("src\\file\\properties\\mysql.properties"));
String line;
while ((line=br.readLine())!=null){
String[] split=line.split("=");
System.out.println(split[0]+" 的值为:"+split[1]);
}
br.close();
}
public static void main(String[] args) throws IOException {
//使用Properties类
Properties properties = new Properties();
properties.load(new FileInputStream("src\\file\\properties\\mysql.properties"));
properties.setProperty("database","mysql");
System.out.println(properties.getProperty("ip"));
properties.list(System.out);
properties.store(new FileWriter("src\\file\\properties\\mysql1.properties"),"comments");
}