一.数据输入输出流
数据输入流:
DataInputStream
数据输出流:
DataOutputStream
这对流的特点是能够读写基本数据类型
以Stream结尾的 一般都是字节流
package org.westos.demo;
import java.io.*;
public class MyTest2 {
public static void main(String[] args) throws IOException {
/*数据输入流:
DataInputStream
数据输出流:
DataOutputStream
这对流的特点是能够读写基本数据类型
以Stream结尾的 一般都是字节流*/
DataOutputStream out = new DataOutputStream(new FileOutputStream("a.txt"));
out.writeInt(100);
out.writeBoolean(true);
out.writeChar('a');
out.writeUTF("aaa");
System.out.println("=============");
//读和写的顺序要保持一致
DataInputStream in = new DataInputStream(new FileInputStream("a.txt"));
int num1 = in.readInt();
System.out.println(num1);
boolean b = in.readBoolean();
System.out.println(b);
char c = in.readChar();
System.out.println(c);
String s = in.readUTF();
System.out.println(s);
}
}
二.内存操作流
A:内存操作流的概述
a:操作字节数组
ByteArrayOutputStream
ByteArrayInputStream
此流关闭无效,所以无需关闭
b:操作字符数组
CharArrayWrite
CharArrayReader
c:操作字符串
StringWriter
StringReader
1.ByteArrayOutputStream和ByteArrayInputStream
(1) ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。
缓冲区会随着数据的不断写入而自动增长。
可使用 toByteArray () 和 toString () 获取数据。
ByteArrayOutputStream()
创建一个新的 byte 数组输出流
不会直接去关联文件,只是在内存中进行数据的读写
关闭 ByteArrayOutputStream 无效
(2)ByteArrayInputStream(byte[] buf)
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
package org.westos.demo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class MyTest3 {
public static void main(String[] args) throws IOException {
/* a:操作字节数组
ByteArrayOutputStream
ByteArrayInputStream
此流关闭无效,所以无需关闭*/
/*
ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。
缓冲区会随着数据的不断写入而自动增长。
可使用 toByteArray () 和 toString () 获取数据。
关闭 ByteArrayOutputStream 无效。*/
/* ByteArrayOutputStream()
创建一个新的 byte 数组输出流*/
//不会直接去关联文件,只是在内存中进行数据的读写
ByteArrayOutputStream out = new ByteArrayOutputStream();
//把字节数组,写入到ByteArrayOutputStream自己所维护的那个字节数组中去
out.write("我爱Java".getBytes());
out.write("老鼠爱大米".getBytes());
out.write("本伟卢氏".getBytes());
//取出ByteArrayOutputStream 他所维护的那个字节数组中的字节数据
byte[] bytes = out.toByteArray();
String s = new String(bytes);
System.out.println(s);
String string = out.toString();
System.out.println(string);
System.out.println("======================");
/* ByteArrayInputStream(byte[] buf)
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。*/
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
out2.write("我爱Java".getBytes());
out2.write("老鼠爱大米".getBytes());
out2.write("本伟卢氏".getBytes());
//取出ByteArrayOutputStream 他所维护的那个字节数组中的字节数据
byte[] allByte = out2.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(allByte);
byte[] epmtyBytes = new byte[1024*8];
int len = in.read(epmtyBytes);
String s1 = new String(epmtyBytes, 0, len);
System.out.println(s1);
/*ByteArrayInputStream in = new ByteArrayInputStream(bytes1);
int len = in.read(bytes1);
String s1 = new String(bytes1,0,len);
System.out.println(s1);*/
in.close();
out.close();
out2.close();
}
}
案例:合并两首歌
方式一:
package org.westos.demo;
import java.io.*;
import java.util.ArrayList;
public class MyTest4 {
public static void main(String[] args) throws IOException {
//合并两首歌
FileInputStream in1 = new FileInputStream("许巍 - 蓝莲花.mp3");
FileInputStream in2 = new FileInputStream("陈一发儿01 - 童话镇.mp3");
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(in1);
list.add(in2);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len=0;
byte[] bytes = new byte[1024*8];
for (FileInputStream in : list) {
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
in.close();
}
//取出两首歌的字节数据
byte[] allByte = out.toByteArray();
//把两首歌的字节数据写入到一个文件中
//取出ByteArrayOutputStream 他所维护的那个字节数组中的字节数据
ByteArrayInputStream bis = new ByteArrayInputStream(allByte);
FileOutputStream out2 = new FileOutputStream("C:\\Users\\user\\Desktop\\歌曲大连唱.mp3");
int len2=0;
byte[] bytes2 = new byte[1024*8];
while ((len2=bis.read(bytes2))!=-1){
out2.write(bytes2,0,len2);
}
out2.close();
}
}
方式二:
package org.westos.demo;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class MyTest5 {
public static void main(String[] args) throws IOException {
//合并多个文件,没有必要使用内存操作流
//合并两首歌
FileInputStream in1 = new FileInputStream("许巍 - 蓝莲花.mp3");
FileInputStream in2 = new FileInputStream("陈一发儿01 - 童话镇.mp3");
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(in1);
list.add(in2);
FileOutputStream out = new FileOutputStream("C:\\Users\\user\\Desktop\\demo\\歌曲大联唱");
int len=0;
byte[] bytes = new byte[1024*8];
for (FileInputStream in : list) {
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
in.close();
}
out.close();
}
}
2.CharArrayWrite和CharArrayReader
操作字符数组
CharArrayWrite 他维护的缓冲区是一个字符数组
CharArrayReader
package org.westos.demo2;
import java.io.CharArrayWriter;
import java.io.IOException;
public class MyTest {
public static void main(String[] args) throws IOException {
/*操作字符数组
CharArrayWriter 他维护的缓冲区是一个字符数组
CharArrayReader*/
CharArrayWriter writer = new CharArrayWriter();
String str = "好好学习";
String str2 = "天天向上";
String str3 = "爱生活";
String str4 = "爱Java";
//把字符串,写入到CharArrayWrite维护的字符数组中去
writer.write(str);
writer.write(str2);
writer.write(str3);
writer.write(str4);
//取出CharArrayWrite所维护的字符数组
char[] chars = writer.toCharArray();
System.out.println(chars);
String s = new String(chars);
System.out.println(s);
System.out.println(writer.toString());
}
}
3.StringWriter和StringReader
操作字符串
StringWriter 他底层用的是SStringBuffer 来充当缓冲区
StringReader
package org.westos.demo2;
import java.io.StringWriter;
public class MyTest2 {
public static void main(String[] args) {
/* 操作字符串
StringWriter 他底层用的是StringBuffer 来充当缓冲区
StringReader*/
StringWriter writer = new StringWriter();
writer.write("aaa");
writer.write("aaa");
writer.write("aaa");
writer.write("aaa");
System.out.println(writer);
System.out.println(writer.toString());
}
}
三.打印流
1.概述
A:打印流的概述
分类:
字节流打印流
字符打印流
B:打印流的特点:单独存在,只能写不能读
a: 打印流只能操作目的地,不能操作数据源(不能进行读取数据)
- b: 可以操作任意数据类型的数据 调用print() 方法可以写任意数据类型
- c: 如果我们启用自动刷新,那么在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
/**
通过以下构造创建对象 能够启动自动刷新 然后调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
* public PrintWriter(OutputStream out, boolean autoFlush) 启动 自动刷新
* public PrintWriter(Writer out, boolean autoFlush) 启动自动刷新
*/
- d: 这个流可以直接对文件进行操作(可以直接操作文件的流: 就是构造方法的参数可以传递文件或者文件路径)
2.字符打印流
PrintWriter
构造方法:
PrintWriter(File file)
使用指定文件创建不具有自动行刷新的新 PrintWriter。
PrintWriter(String fileName)
创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。参数2:true开启自动刷新
PrintWriter(Writer out, boolean autoFlush)
创建新 PrintWriter。参数2:true开启自动刷新
如果启用了自动刷新,则只有在调用 println、printf 或 format
的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。
package org.westos.demo2;
import java.io.IOException;
import java.io.PrintWriter;
public class MyTest3 {
public static void main(String[] args) throws IOException {
//打印流,单独存在,只能写不能读
//字节打印流,字符打印流
/*字符打印流:
PrintWriter
构造方法:
PrintWriter(File file)
使用指定文件创建不具有自动行刷新的新 PrintWriter。
PrintWriter(String fileName)
创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
* */
PrintWriter writer = new PrintWriter("b.txt");
writer.write("本伟卢氏");
writer.write("\r\n");
writer.write(100);
writer.write("\r\n");
writer.write(91);
writer.write("\r\n");
//写入并换行
writer.println(100);
writer.println(65);
writer.println(65);
writer.print(true);
writer.write("\r\n");
writer.flush();
}
}
package org.westos.demo2;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class MyTest4 {
public static void main(String[] args) throws IOException {
/* PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。
PrintWriter(Writer out, boolean autoFlush)
创建新 PrintWriter。*/
//参数2:true开启自动刷新
/* 如果启用了自动刷新,则只有在调用 println、printf 或 format
的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。*/
PrintWriter writer = new PrintWriter(new FileWriter("c.txt"),true);
writer.write("1111");
writer.write("2222");
writer.flush();
writer.printf("3333");
writer.println("aaaa");
writer.println("aaaa");
writer.println("aaaa");
writer.println("aaaa");
writer.close();
}
}
3.字节打印流
PrintStream 字节打印流 单个的,只能输出数据。
构造方法:
PrintStream(File file)
创建具有指定文件且不带自动行刷新的新打印流。
PrintStream(File file, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
PrintStream(OutputStream out)
创建新的打印流。
PrintStream(String fileName)
创建具有指定文件名称且不带自动行刷新的新打印流。
PrintStream(String fileName, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
package org.westos.demo2;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
public class MyTest5 {
public static void main(String[] args) throws IOException {
/* PrintStream(File file)
创建具有指定文件且不带自动行刷新的新打印流。
PrintStream(File file, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
PrintStream(OutputStream out)
创建新的打印流。
PrintStream(String fileName)
创建具有指定文件名称且不带自动行刷新的新打印流。
PrintStream(String fileName, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。*/
//new一个字节打印流,与传入的文件相关联,调用println()方法就是写入数据到关联的文件中
PrintStream stream = new PrintStream("d.txt");
stream.println(100);
stream.print(true);
stream.print(true);
stream.print(true);
stream.println("aaaa");
stream.flush();
stream.close();
System.out.println("=======================");
//我们通过System类中的静态变量in 可以获取出一个PrintStream字节打印流 调用输出的方法时输出的目的地是屏幕
// System类的属性 out标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出
InputStream in = System.in;
PrintStream out = System.out;
out.write("111".getBytes());
out.println(100);
out.println(200);
out.println(200);
out.println(200);
}
}
案例:使用打印流来复制文件
package org.westos.demo2;
import java.io.*;
public class MyTest6 {
public static void main(String[] args) throws IOException {
//使用打印流来复制文本文件
PrintWriter writer = new PrintWriter(new FileWriter("MyTest2.java"));
BufferedReader reader = new BufferedReader(new FileReader("MyTest.java"));
String s=null;
while((s=reader.readLine())!=null){
writer.println(s);
}
reader.close();
writer.close();
}
}
四.标准输入输出流
1.概述
A:标准输入输出流概述
在System这个类中存在两个静态的成员变量:
- public static final InputStream in: 标准输入流, 对应的设备是键盘
此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
- public static final PrintStream out: 标准输出流 , 对应的设备就是显示器
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的孙子类FilterOutputStream 的子类.
package org.westos.demo3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) throws IOException {
/* System类中的静态成员变量:
public static final InputStream in: 标准输入流, 对应的设备是键盘
此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。*/
/*Scanner(File source)
构造一个新的 Scanner,它生成的值是从指定文件扫描的。
Scanner(InputStream source)
构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。*/
//Scanner scanner = new Scanner(System.in);
//Scanner类关联文件
Scanner sc = new Scanner(new File("MyTest.java"));
while (sc.hasNextLine()){
String s = sc.nextLine();
System.out.println(s);
}
}
}
案例:用Scanner和PrintWriter 配合来复制文件
package org.westos.demo3;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class MyTest2 {
public static void main(String[] args) throws IOException {
//用Scanner和PrintWriter 配合来复制文件
//Scanner关联文件
Scanner sc = new Scanner(new File("MyTest.java"));
PrintWriter writer = new PrintWriter("MyTest3.java");
while (sc.hasNextLine()) {
String s = sc.nextLine();
writer.println(s);
}
sc.close();
writer.close();
}
}
2.键盘录入的两种方式
package org.westos.demo3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class MyTest3 {
public static void main(String[] args) throws IOException {
/*
键盘录入的二种方式
in
public static final InputStream in“标准”输入流。
此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
Scanner scanner = new Scanner(System.in);
*/
//in返回的是InputStream类型
//键盘录入的第一种方式
//Scanner sc = new Scanner(System.in);
//从键盘上读取数据,键盘录入的第二种方式
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入数据");
String s = reader.readLine();
System.out.println(s);
//定义一个结束标记
if (s.equals("再见")){
break;
}
}
}
}
3.注意事项
获取System下的in成员变量
InputStream in = System.in ;
in是一个字节输入流对象,那么我们就可以通过这个字节输入流对象进行读取键盘录入的数据.
那么我们既然要读取数据,之前我们讲解了两种读取数据的方式:
1. 一次读取一个字节
2. 一次读取一个字节数组
那么我们在这个地方使用那种读取方式. 经过分析,这两种读取方式都不太合适.因为数据是客户通过键盘录入
进来的,而我们希望直接读取一行数据. 而既然要读取一行数据,那么我们就需要使用readLine方法,而这个方法
是属于BufferedReader的方法,而我们就需要创建一个BufferedReader对象进行读取数据.而我们这in有属于
字节流,而创建BufferedReader对象的时候需要一个字符流,而我们就需要将这个字节流转换成字符流,那么既然
要对其进行转换,那么就需要使用转换流. 需要使用InputStreamReader
五.随机访问流
1.概述
A:随机访问流概述
RandomAccessFile概述 最大特点 能读能写
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
支持对随机访问文件的读取和写入。
RandomAccessFile的父类是Object , 这个流对象可以用来读取数据也可以用来写数据.可以操作任意数据类型的数据.
我们可以通过getFilePointer方法获取文件指针,并且可以通过seek方法设置文件指针
RandomAccessFile概述 最大特点 能读能写而且有一个文件指针,可以控制指针的位置。
此类的实例支持对随机访问文件的读取和写入。
随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。
存在指向该隐含数组的光标或索引,称为文件指针;
输入操作从文件指针开始读取字节,
并随着对字节的读取而前移此文件指针。
构造方法:
RandomAccessFile(String name, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
package org.westos.demo4;
import java.io.IOException;
import java.io.RandomAccessFile;
public class MyTest {
public static void main(String[] args) throws IOException {
//随机访问流
// RandomAccessFile概述 最大特点 能读能写而且有一个文件指针,可以控制指针的位置。
/* 此类的实例支持对随机访问文件的读取和写入。
随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。
存在指向该隐含数组的光标或索引,称为文件指针;
输入操作从文件指针开始读取字节,
并随着对字节的读取而前移此文件指针。*/
/*RandomAccessFile(String name, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。*/
//rw表示可读可写
RandomAccessFile file = new RandomAccessFile("e.txt","rw");
file.writeInt(200);
file.writeBoolean(true);
file.writeChar('a');
//写入中文,注意会多写两个字节
file.writeUTF("本伟卢氏");
System.out.println("===================");
//读取文件,注意读写顺序要一致,怎么写的就怎么读
RandomAccessFile file2 = new RandomAccessFile("e.txt", "rw");
System.out.println(file2.readInt());
long filePointer = file2.getFilePointer();
System.out.println("文件指针的位置"+filePointer);//4
System.out.println(file2.readBoolean());
filePointer = file2.getFilePointer();
System.out.println("文件指针的位置"+filePointer);//5
System.out.println(file2.readChar());
filePointer = file2.getFilePointer();
System.out.println("文件指针的位置"+filePointer);//7
System.out.println(file2.readUTF());
filePointer = file2.getFilePointer();
System.out.println("文件指针的位置"+filePointer);//21
file.close();
file2.close();
}
}
案例:复制文件,可以暂停继续
package org.westos.demo4;
import jdk.nashorn.internal.runtime.ECMAException;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
public class MyTest2 {
public static void main(String[] args) throws IOException {
//复制文件,可以暂停继续
//下载到一半时,暂停下载,明天继续下载
RandomAccessFile file = new RandomAccessFile("陈一发儿01 - 童话镇.mp3","rw");
File file1 = new File("C:\\Users\\user\\Desktop\\陈一发儿02 - 童话镇.mp3");
RandomAccessFile file2 = new RandomAccessFile(file1, "rw");
//严谨性判断,如果上次没复制完的文件,不存在了,就从头开始复制
/* if(!file1.exists()||fil1.length()<上次记录的字节数){
//把文件指针设置为0 从头开始读
file.seek(0);
//把文件指针设置为0 从头开始写
file2.seek(0);
}else{
//从配置文件中读取上次断开的位置
file.seek(3001);
//从配置文件中读取上次断开的位置
fiel2.seek(3301);
}*/
int len=0;
int i=0;
try {
while ((len=file.read())!=-1){
/*模拟一个异常,或模拟用户暂停
if(i++>3000){
System.out.println(1/0);
}*/
file2.write(len);
}
}catch (Exception e){
//当复制或下载文件过程当中遇到了异常或用户手动暂停,我们zt");
writer.println(filePointer);
writer.flush();
writer.close();
e.printStackTrace();
}
}
}
作业:把一个文件复制三份
方式1
package org.westos.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyTest {
public static void main(String[] args) throws IOException {
//如何将一个文件复制三份
for (int i = 1; i <= 3; i++) {
FileInputStream in = new FileInputStream("Student.java");
long l = System.currentTimeMillis();
String s = String.valueOf(l);
FileOutputStream out = new FileOutputStream(s);
int len=0;
byte[] bytes = new byte[1024 * 8];
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
out.flush();
}
out.close();
in.close();
}
}
}
六.序列化和反序列化流
1.概述
A:序列化流的概述
所谓的序列化:就是把对象通过流的方式存储到文件中.注意:此对象 要重写Serializable 接口才能被序列化
反序列化:就是把文件中存储的对象以流的方式还原成对象
序列化流: ObjectOutputStream
反序列化流: ObjectInputStream
序列化和反序列化
序列化:将Java对象保存到文件中
反序列化:将文件中的对象,读取回内存。
这对流能够对Java对象进行读写
序列化流:
ObjectOutputStream
反序列化流:
ObjectInputStream
像这样一个接口中如果没有方法,那么这样的接口我们将其称之为标记接口(用来给类打标记的,相当于猪肉身上盖个章)
一个对象可以被序列化的前提是这个对象对应的类必须实现Serializable接口
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
package org.westos.demo;
import java.io.*;
public class MyTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
/* 序列化和反序列化
序列化:将Java对象保存到文件中
反序列化:将文件中的对象,读取回内存。
此对象 要重写Serializable 接口才能被序列化
这对流能够对Java对象进行读写
序列化流:
ObjectOutputStream
反序列化流:
ObjectInputStream
构造方法:
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。*/
Student student = new Student("本伟", 33,'男');
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("student.txt"));
//把Java对象写到文件中
//1.当我们去序列化一个Java对象时,要求我们这个对象所对应的类,必须实现一个序列化接口Serializable
out.writeObject(student);
System.out.println("=================");
ObjectInputStream in = new ObjectInputStream(new FileInputStream("student.txt"));
Object object = in.readObject();
Student s= (Student) object;
System.out.println(s.getName());
out.close();
in.close();
}
}
package org.westos.demo;
import java.io.*;
import java.util.ArrayList;
public class MyTest2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student1 = new Student("李白", 22,'男');
Student student2 = new Student("杜甫", 24,'男');
Student student3 = new Student("王维", 23,'女');
//如果我们要序列化多个对象,我们一个个去存这个对象。我们可以把这多个对象,
// 放到一个容器中,把容器序列化到文件中
ArrayList<Student> list = new ArrayList<>();
list.add(student1);
list.add(student2);
list.add(student3);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("a.txt"));
out.writeObject(list);
ObjectInputStream in = new ObjectInputStream(new FileInputStream("a.txt"));
Object object = in.readObject();
ArrayList<Student> arrayList= (ArrayList<Student>) object;
Student student = arrayList.get(0);
System.out.println(student);
in.close();
out.close();
}
}
2.序列化时候的黄色警告线问题
- 我们的一个类可以被序列化的前提是需要这个类实现Serializable接口,就需要给这个类添加一个标记.
- 在完成序列化以后,序列化文件中还存在一个标记,然后在进行反序列化的时候,
会验证这个标记和序列化前的标记是否一致,如果一致就正常进行反序列化,如果
- 不一致就报错了. 而现在我们把这个类做了修改,将相当于更改了标记,而导致这两个标记不一致,就报错了.
-
- 解决问题: 只要让这个两个标记一致,就不会报错了吧
- 怎么让这两个标记一致呢? 不用担心,很简单,难道你们没有看见黄色警告线吗? alt+enter, 生成出来
private static final long serialVersionUID = -7602640005373026150L;
Java序列化的机制是通过判断类的serialVersionUID来验证版本是否一致的。
在进行反序列化时,JVM会把传来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同说明是一致的,可以反序列化;
否则,会出现InvalidCastException。
package org.westos.demo;
import java.io.*;
public class MyTest3 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化时候的黄色警告线问题
//writeData();
//当writeData()方法执行完后,修改Student类,例如去掉age的权限修饰符
//读取时会报InvalidClassException异常
readData();
}
private static void readData() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("b.txt"));
Object object = in.readObject();
Student s= (Student) object;
System.out.println(s);
in.close();
}
private static void writeData() throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("b.txt"));
Student student = new Student("李白", 22, '男');
//将student对象序列化保存到对象中
out.writeObject(student);
out.close();
}
}
3.transient关键字
如何让对象的成员变量不被序列化:对象不被存储,例如使用transient关键字存储引用类型
存储的就是null
使用transient关键字声明不需要序列化的成员变量
private transient int age ;// 可以阻止成员变量的序列化使用transient
package org.westos.demo;
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private transient int age;
private char sex;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public Student(String name, int age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
------------------------------
package org.westos.demo;
import java.io.*;
public class MyTest4 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeData();
readData();
}
private static void readData() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("b.txt"));
Object object = in.readObject();
Student s= (Student) object;
System.out.println(s);
in.close();
}
private static void writeData() throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("b.txt"));
Student student = new Student("李白", 22, '男');
//将student对象序列化保存到对象中
out.writeObject(student);
out.close();
}
}
七.Properties属性集合
1.概述
A:Properties的概述
查看API
Properties 类表示了一个持久的属性集。
Properties 可保存在流中或从流中加载。
属性列表中每个键及其对应值都是一个字符串。
Properties父类是Hashtable
- 属于双列集合,这个集合中的键和值都是字符串 Properties不能指定泛型
- 属性集合
Properties 继承自Hashtable 是一个双列集合
我们经常使用这个集合来读取配置文件。
Properties 规定了键和值都是String类型
2.Properties的特殊功能使用
A:Properties的特殊功能
public Object setProperty(String key,String value)
public String getProperty(String key)
public Set<String> stringPropertyNames()
package org.westos.demo;
import java.util.Properties;
public class MyTest {
public static void main(String[] args) {
/*属性集合
Properties 继承自Hashtable 是一个双列集合
我们经常使用这个集合来读取配置文件。
Properties 规定了键和值都是String类型*/
Properties properties = new Properties();
//使用继承的方法读取
properties.put("aaa","001");
properties.put("bbb","002");
properties.put("ccc","003");
Object aaa = properties.get("aaa");
String s= (String) aaa;
System.out.println(s);
System.out.println("===================");
//使用特有的方法进行读取
Properties properties2 = new Properties();
properties2.setProperty("aaa","001");
properties2.setProperty("bbb","002");
String s2 = properties2.getProperty("aaa");
System.out.println(s2);
System.out.println("===========");
//如果通过键找不到值,返回的是一个null
String s3 = properties2.getProperty("ccc");
System.out.println(s3);
//参数2:是一个默认值,如果通过键没有找到这个对应的值。就返回默认值。
String ddd = properties2.getProperty("ddd", "默认");
System.out.println(ddd);
}
}
3.存储双列集合中的数据到文本文件中
package org.westos.demo;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.function.Consumer;
public class MyTest2 {
public static void main(String[] args) throws IOException {
/*把双列集合中的数据,存储到文本文件中保存。
存储的样子如下
usename=libai
password=123456
email=zpc111@163.com*/
HashMap<String, String> hm = new HashMap<>();
hm.put("usename","libai");
hm.put("password","123456");
hm.put("email","zpc111@163.com");
//开启自动刷新
PrintWriter writer = new PrintWriter(new FileOutputStream("user.properties"),true);
//获取所有的键
Set<String> keys = hm.keySet();
for (String key : keys) {
String value = hm.get(key);
System.out.println(key+"==="+value);
}
//拿到每一个节点
Set<Map.Entry<String, String>> entry = hm.entrySet();
for (Map.Entry<String, String> node : entry) {
String key = node.getKey();
String value = node.getValue();
System.out.println(key+"=="+value);
writer.println(key+"==="+value);
}
System.out.println("==============");
//通常Properties 集合用来存放配置文件
Properties properties = new Properties();
properties.setProperty("aaa","001");
properties.setProperty("bbb","002");
properties.setProperty("ccc","003");
//我们把属性集合中的键值对数据存到配置文件中
properties.store(new FileWriter("yonghu.properties"),null);
}
}
4.Properties的load()和store()功能
A:Properties的load()和store()功能
Properties和IO流进行配合使用:
- public void load(Reader reader):把文件中的键值对加载到集合中
- public void store(Writer writer, String comments)将键值对的属性集合存储到配置文件
package org.westos.demo;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class MyTest4 {
public static void main(String[] args) throws IOException {
//public void store(Writer writer, String comments) 存储Properties对象到文本文件
Properties properties = new Properties();
properties.setProperty("username","李白");
properties.setProperty("password","123456");
properties.setProperty("hobby","足球");
properties.store(new FileWriter("aaa.properties"),null);
}
}
5.读取properties配置文件到内存
读取properties配置文件到内存
Properties读取.properties属性配置文件,要求键与值之间用等号拼接。
package org.westos.demo;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Properties;
public class MyTest5 {
public static void main(String[] args) throws IOException {
//我有一个配置文件,配置文件是键值对数据 键=值
//把配置文件中的数据读取到双列集合中
//要求键与值之间用等号拼接。
HashMap<String, String> hashMap = new HashMap<>();
BufferedReader reader = new BufferedReader(new FileReader("user.properties"));
String s = reader.readLine();
System.out.println(s);//password===123456
String[] split = s.split("===");
//System.out.println(split);打印地址值
hashMap.put(split[0],split[1]);
System.out.println(hashMap);
System.out.println("===================");
/*使用 Properties 属性集合中的方法,直接就读取到集合里面去了
Properties 属性集合来取读取配置文件,要求配置文件的中的数据 键和值是以=来拼接的
一般属性配置文件的后缀名会以 .properties作为扩展名*/
Properties properties = new Properties();
//把配置文件中的键值对数据读取到属性集合中
properties.load(new FileReader("aaa.properties"));
System.out.println(properties);
String username = properties.getProperty("username");
System.out.println(username);
}
}
package org.westos.demo2;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class MyTest {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("username","李白");
properties.setProperty("password","123456");
properties.setProperty("hobby","足球");
/*
* - public void load(Reader reader): 从配置文件中读取键值对
- public void store(Writer writer, String comments)将键值对的属性集合存储到配置文件
* */
properties.store(new FileWriter("ccc.properties"),null);
Properties properties2 = new Properties();
properties2.load(new FileReader("ccc.properties"));
String password = properties2.getProperty("password");
System.out.println(password);
}
}
安例演示
需求:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”
package org.westos.demo2;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class MyTest2 {
public static void main(String[] args) throws IOException {
/* 例演示
需求:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”*/
Properties properties = new Properties();
//把文件中的键值对加载到集合中
properties.load(new FileReader("ccc.properties"));
Set<Object> keySet = properties.keySet();
for (Object key : keySet) {
if (key.equals("lisi")){
properties.setProperty((String) key,"100");
}
}
//更改完集合,存储到文件中
properties.store(new FileWriter("ccc.properties"),null);
}
}
八.SequenceInputStream
1.概述
SequenceInputStream
表示其他输入流的逻辑串联。
它从输入流的有序集合开始,
并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,
依次类推,直到到达包含的最后一个输入流的文件末尾为止
a:构造方法
SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),
以提供从此 SequenceInputStream 读取的字节。
b:构造方法
SequenceInputStream(Enumeration<? extends InputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
2.合并两个文件
package org.westos.demo2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
public class MyTest3 {
public static void main(String[] args) throws IOException {
/*
将a.txt和b.txt两个文本文件的内容合并到c.txt
*/
/* SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,
并从第一个输入流开始读取,直到到达文件末尾,
接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
*/
FileInputStream in1 = new FileInputStream("a.txt");
FileInputStream in2 = new FileInputStream("b.txt");
/*构造方法:
SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream
(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
* */
SequenceInputStream in = new SequenceInputStream(in1,in2);
FileOutputStream out = new FileOutputStream("c.txt");
int len=0;
byte[] bytes = new byte[1024*8];
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
out.flush();
}
in.close();
out.close();
}
}
3.合并多个文件
package org.westos.demo2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
public class MyTest4 {
public static void main(String[] args) throws IOException {
//合并两个配置文件
FileInputStream in1 = new FileInputStream("a.txt");
FileInputStream in2 = new FileInputStream("b.txt");
FileInputStream in3 = new FileInputStream("ccc.properties");
FileInputStream in4 = new FileInputStream("user.properties");
SequenceInputStream in = new SequenceInputStream(in1,in2);
SequenceInputStream in5 = new SequenceInputStream(in, in3);
SequenceInputStream in6 = new SequenceInputStream(in5, in4);
FileOutputStream out = new FileOutputStream("all.properties");
int len=0;
byte[] bytes = new byte[1024*8];
while ((len=in6.read(bytes))!=-1){
out.write(bytes,0,len);
out.flush();
}
in6.close();
out.close();
}
}
4.迭代
SequenceInputStream(Enumeration < ? extends InputStream > e)
通过记住参数来初始化新创建的 SequenceInputStream,
该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
package org.westos.demo2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;
public class MyTest5 {
public static void main(String[] args) throws IOException {
/*SequenceInputStream(Enumeration < ? extends InputStream > e)
通过记住参数来初始化新创建的 SequenceInputStream,
该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。*/
FileInputStream in1 = new FileInputStream("ccc.properties");
FileInputStream in2 = new FileInputStream("user.properties");
FileInputStream in3 = new FileInputStream("yonghu.properties");
//把多个输入流,放到集合vector中
Vector<FileInputStream> vector = new Vector<>();
vector.add(in1);
vector.add(in2);
vector.add(in3);
//获取迭代器
Enumeration<FileInputStream> elements = vector.elements();
//然后把迭代器传给序列流,他就会去迭代集合中的流
SequenceInputStream in = new SequenceInputStream(elements);
FileOutputStream out = new FileOutputStream("out.properties");
int len=0;
byte[] bytes = new byte[1024*8];
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
in.close();
out.close();
}
}