一、缓冲流
1、缓冲流:
字节输入缓冲流: BufferedInputStream
字节输出缓冲流: BufferedOutputStream
字符输入缓冲流: BufferedReader
字符输出缓冲流: BufferedWriter
缓冲流的特点是快,可以提高读写的效率,原因是因为内部具有一个缓冲区。
其实缓冲流本身并不具备读或者写的功能,他真正的作用是给其他流提供加速。
使用步骤:
1. 创建缓冲流对象
2. 调用read方法读取或者调用write方法写数据。(读取和写数据的方法和我们之前学的一模一样)
3. 释放资源。
字节缓冲流的构造方法:
BufferedInputStream(InputStream in): 参数需要传递一个字节输入流。
BufferedOutputStream(OutputStream out):参数需要传递一个字节输出流。
和之前创建对象的区别: 之前构造方法位置可以直接传递字符串,现在要传递一个流对象。
public class Demo02BufferedStream {
public static void main(String[] args) throws IOException {
//创建字节输入缓冲流对象,用来读取
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day10\\aa.jpg"));
//创建字节输出缓冲流,用来写
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day10\\bb.jpg"));
long start = System.currentTimeMillis();
//开始读写,每使用缓冲输入流读取一个字节,那么就将读取到的字节写到目的地中。
int i; //定义变量,用来接收读取到的字节
while((i = bis.read()) != -1) {
//将读取到的字节写到目的地中
bos.write(i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
//释放资源
bos.close();
bis.close();
}
}
2、 使用字节缓冲流一次读写一个字节数组的方式复制文件
public class Demo03BufferedStream {
public static void main(String[] args) throws IOException {
//创建字节输入缓冲流,用来读取
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day10\\aa.jpg"));
//创建字节输出缓冲流,用来写
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day10\\bb.jpg"));
long start = System.currentTimeMillis();
//开始读写,一次读写一个字节数组
byte[] bArr = new byte[1024 * 8];
int len;
while ((len = bis.read(bArr)) != -1) {
//将读取到的内容写入到目的地文件中
bos.write(bArr, 0, len);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
//释放资源
bos.close();
bis.close();
}
}
3、字符缓冲流:
字符输入缓冲流: BufferedReader
字符输出缓冲流: BufferedWriter
使用步骤:
1. 创建缓冲流对象
2. 调用read读取或者调用write写数据。读取或者写的方法和之前学的一模一样
3. 释放资源。
BufferedReader构造方法:
BufferedReader(Reader in): 构造方法需要传递一个字符输入流。
BufferedWriter构造方法:
BufferedWriter(Writer out):构造方法需要传递一个字符输出流。
public class Demo01BufferedStream {
public static void main(String[] args) throws IOException {
method2();
}
//BufferedReader的使用
public static void method2() throws IOException {
//创建BufferedReader对象
BufferedReader br = new BufferedReader(new FileReader("day10\\file02.txt"));
//开始读取
//一次读取一个字符
/*
int i;
while((i = br.read()) != -1) {
//把读取到的内容进行打印
System.out.print((char)i);
}
*/
//一次读取一个字符数组
int len;
char[] cArr = new char[1024];
while ((len = br.read(cArr)) != -1) {
System.out.print(new String(cArr, 0, len));
}
//释放资源
br.close();
}
//BufferedWriter的使用
public static void method1() throws IOException {
//创建一个BufferedWriter对象
BufferedWriter bw = new BufferedWriter(new FileWriter("day10\\file02.txt"));
//调用方法,写数据
bw.write("你好");
//释放资源
bw.close();
}
}
4、字符缓冲流中的特殊作用:
BufferedWriter里面有一个方法,叫做newLine,可以实现一个跨平台的换行
void newLine(): 写一个跨平台换行
BufferedReader里面有一个方法,叫做readLine,可以一次读取一行数据。
String readLine() 读一行数据。 并且把读取到的数据返回。 如果读取结束返回 null。
注意readLine方法不会读取换行符,只会读取换行符之前的内容.
public class Demo02BufferedStream {
public static void main(String[] args) throws IOException {
method2();
}
//String readLine() 读一行数据。 并且把读取到的数据返回。 如果读取结束返回 null。
public static void method2() throws IOException {
//创建一个BufferedReader对象
BufferedReader br = new BufferedReader(new FileReader("day10\\file03.txt"));
//使用循环一次读取一行数据
//定义变量,用来保存读取到的这行数据
String line;
//使用循环读取
while ((line = br.readLine()) != null) {
/*
条件位置做了以下事情
1. 调用readLine方法,读取一行数据
2. 将读取到的数据赋值给变量line
3. 判断变量line的数据是否为null,如果不是null表示读取到了数据,那么就处理
*/
System.out.println(line);
}
/*
//调用readLine,一次读取一行数据
String line = br.readLine();
System.out.println(line); //床前明月光
line = br.readLine();
System.out.println(line); //疑是地上霜
line = br.readLine();
System.out.println(line); //null
*/
//释放资源
br.close();
}
//void newLine(): 写一个跨平台换行
public static void method1() throws IOException {
//创建BufferedWriter对象
BufferedWriter bw = new BufferedWriter(new FileWriter("day10\\file03.txt"));
//调用write方法写数据
bw.write("床前明月光");
bw.newLine();//跨平台的换行
bw.write("疑是地上霜");
//释放资源
bw.close();
}
}
5、将出师表.txt中的内容恢复顺序,然后写入到一个新的文件中。
出师表.txt中的内容特点:
1. 每一行数据都是 序号.课文内容
2. 序号是不重复
思路:
1. 定义一个Map集合,key是序号,value是课文内容。
2. 创建BufferedReader对象,用来读取
3. 读取文件中的内容,一次读取一行数据。
4. 将读取到的这行数据使用. 切割,得到这行数据的序号以及课文内容。
5. 将读取到的序号和课文内容放入到Map集合中。
6. 关闭输入流。
7. 创建一个BufferedWriter,用来写
8. 使用for循环手动走一遍1-9.(其实就是文件中的序号, 也是Map集合中的key)
9. 去Map集合中根据这个key拿到对应的value
10. 将key和value使用. 进行分割重新写入到新的文件中
11. 换行
12. 刷新
13. 释放资源
public class Demo03BufferedStreamTest {
public static void main(String[] args) throws IOException {
//定义一个Map集合,key是序号,value是课文内容。
Map<Integer, String> map = new HashMap<>();
//创建BufferedReader对象,用来读取
BufferedReader br = new BufferedReader(new FileReader("day10\\出师表.txt"));
//读取文件中的内容,一次读取一行数据。
String line;
while ((line = br.readLine()) != null) {
//line中保存了读取到的数据,我们要使用.进行切割得到对应的序号以及课文内容
//split方法是在根据正则表达式切割, .是正则表达式中的特殊字符,需要进行转义
//strArr[0] 是序号, strArr[1] 是课文内容
String[] strArr = line.split("\\.");
//将读取到的序号和课文内容放入到Map集合中
Integer id = Integer.parseInt(strArr[0]);
map.put(id, strArr[1]);
}
//关闭输入流。
br.close();
//创建一个BufferedWriter,用来写
BufferedWriter bw = new BufferedWriter(new FileWriter("day10\\outTeacherTable.txt"));
//使用for循环手动走一遍1-9.(其实就是文件中的序号, 也是Map集合中的key)
for(int i = 1; i <= map.size(); i++) {
//去Map集合中根据这个key拿到对应的value
String content = map.get(i);
//将key和value使用 . 进行分割重新写入到新的文件中
bw.write(i + "." + content);
//换行
bw.newLine();
//刷新
bw.flush();
}
//释放资源
bw.close();
}
}
二、转换流
1、InputStreamReader表示转换流。 用来读, 可以将文件中的数据按照【指定编码】读取到Java程序中。
InputStreamReader构造方法:
InputStreamReader(InputStream in): 需要传递一个字节输入流。 会采用平台的默认编码进行读取。
InputStreamReader(InputStream in, String charsetName): 第一个参数是字节输入流。 第二个参数表示编码方式。
转换流其实本身也并不具备读或者写的功能,转换流做的事情其实是查询后码表转码的过程。
使用步骤:
1. 创建一个InputStreamReader对象
2. 调用read方法读取
3. 释放资源。
注意:如果指定的编码方式不存在,那么就会抛出异常
public class Demo02InputStreamReader {
public static void main(String[] args) throws IOException {
// readGBK();
readUTF8();
}
//使用转换流读取UTF-8格式的文件
public static void readUTF8() throws IOException {
//创建一个转换流对象
//构造方法没有指定编码,那么采用的就是默认编码 utf-8
//InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\file02-utf8.txt"));
//也可以单独指定一个UTF-8编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\file02-utf8.txt"), "utf-8");
//开始读取
//一次读取一个字符
int i;
while((i = isr.read()) != -1) {
//打印
System.out.print((char)i);
}
//释放资源
isr.close();
}
//使用转换流读取GBK编码的文件
public static void readGBK() throws IOException {
//创建一个InputStreamReader对象,指定要读取的编码方式
InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\file01-gbk.txt"), "gbk");
//InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\file01-gbk.txt"), "utf-8");
//开始读取
//一次读取一个字符
int i;
while((i = isr.read()) != -1) {
//打印
System.out.print((char)i);
}
//释放资源
isr.close();
}
}
2、OutputStreamWriter也是转换流, 用来写, 可以指定编码进行写入操作。
OutputStreamWriter构造方法:
OutputStreamWriter(OutputStream out): 参数传递字节输出流。 会采用平台默认编码方式进行写入
OutputStreamWriter(OutputStream out, String charsetName): 参数传递字节输出流。 第二个参数charsetName为要写的编码方式.
使用步骤:
1. 创建OutputStreamWriter对象,指定要写入的编码方式
2. 调用write方法,写数据
3. 释放资源
public class Demo03OutputStreamWriter {
public static void main(String[] args) throws IOException {
//writeGBK();
writeUTF8();
}
//以UTF-8方式写数据
public static void writeUTF8() throws IOException {
//创建一个OutputStreamWriter对象
//不指定编码,采用的是idea默认编码utf-8
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\file04-utf8.txt"));
//也可以指定编码,编码方式为utf-8
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\file04-utf8.txt"), "utf-8");
//调用write写
osw.write("你好");
//释放资源
osw.close();
}
//定义方法,以GBK方式写入
public static void writeGBK() throws IOException {
//创建OutputStreamWriter对象,指定要写入的编码方式
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\file03-gbk.txt"), "gbk");
//调用write方法写数据。
osw.write("你好");
//释放资源
osw.close();
}
}
3、将GBK编码的文本文件,转换为UTF-8编码的文本文件。
思路:
1. 创建一个转换流,用来读取GBK编码的文件。
2. 创建一个转换流,用来向UTF-8文件中写数据。
3. 读取GBK编码的文件, 将读取出来的内容写入到UTF-8文件中即可.
4. 释放资源
public class Demo04Test {
public static void main(String[] args) throws IOException {
//创建一个转换流,用来读取GBK编码的文件。
InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\file05-test.txt"), "gbk");
//创建一个转换流,用来写UTF-8编码的文件
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\file06-test.txt"), "utf-8");
//开始读写,采用gbk的方式从gbk编码的文件中读取数据
int i;
while((i = isr.read()) != -1) {
//i就是读取到的字符.
//把这个字符以UTF-8的方式写到目的地文件
osw.write(i);
}
//释放资源
osw.close();;
isr.close();
}
}
三、序列化流
1、ObjectOutputStream叫做序列化流,可以将Java程序中的对象写到文件中。
序列化流本身也并不具备读或者写的功能,它的作用是把对象转成字节。
ObjectOutputStream 构造方法:
ObjectOutputStream(OutputStream out):参数需要传递一个字节输出流对象。
写对象的方法:
void writeObject(Object obj): 向文件中写入对象
使用步骤:
1. 创建序列化流对象。
2. 调用方法,向文件中写一个对象
3. 释放资源。
注意:
要序列化的对象, 它的类必须实现Serializable接口。 如果没有实现这个接口,那么会抛出异常
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws IOException {
//创建序列化流对象。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10\\file04-obj.txt"));
//低啊用writeObject方法写一个Person对象
Person p = new Person("大幂幂", 34);
oos.writeObject(p);
//释放资源
oos.close();
}
}
2、ObjectInputStream叫做反序列化流, 可以将文件中的对象读取到Java程序中
ObjectInputStream构造方法:
ObjectInputStream(InputStream in): 参数需要传递一个字节输入流。
读取对象的方法:
Object readObject(): 读取一个对象。
使用步骤:
1. 创建ObjectInputStream对象
2. 调用readObject方法,读取文件中保存的对象
3. 释放资源
当调用readObject方法读取对象的时候,如果这个对象的类不存在了,那么就会抛出ClassNotFoundException
public class Demo02ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day10\\file04-obj.txt"));
//调用readObject方法,读取文件中保存的对象
Object obj = ois.readObject();
Person p = (Person)obj;
System.out.println(p.getName() + "-" + p.getAge());
//释放资源
ois.close();
}
}
3、 注意:
1. static修饰的成员不能被序列化。
2. 如果希望某个成员变量不会被序列化,那么同时又不希望使用static关键字。 我们可以使用
transient关键,这个关键字表示瞬态。 被transient修饰的成员变量不会被序列化。
public class Demo03StaticAndTransient {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//writeObject();
readObject();
}
//读对象
public static void readObject() throws IOException, ClassNotFoundException {
//创建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day10\\file05-obj.txt"));
//调用readObject方法读取对象
Object obj = ois.readObject();
Person p = (Person)obj;
System.out.println(p.getName() + "-" + p.getAge());
//释放资源
ois.close();
}
//写对象
public static void writeObject() throws IOException {
//创建序列化流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10\\file05-obj.txt"));
//调用方法,写对象
oos.writeObject(new Person("柳岩", 20));
//释放资源
oos.close();
}
}
public class Demo04ObjectStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//writeObject();
readObject();
}
//从文件中读取对象
public static void readObject() throws IOException, ClassNotFoundException {
//创建一个ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day10\\file06-obj.txt"));
//调用readObject方法读取对象
Object obj = ois.readObject();
Person p = (Person)obj;
System.out.println(p.getName() + "-" + p.getAge());
//释放资源
ois.close();
}
//向文件中写一个对象
public static void writeObject() throws IOException {
//创建一个ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10\\file06-obj.txt"));
//调用writeObject方法,向文件中写Person对象
oos.writeObject(new Person("大幂幂", 30));
//释放资源
oos.close();
}
}
4、练习: 将存放多个Person对象的集合写入到file07-test.txt文件中。
在反序列化,读取文件中的集合对象,然后对集合中的内容进行遍历
思路:
1. 创建集合保存Person
2. 向集合中添加Person对象
3. 创建序列化流ObjectOutputStream对象
4. 调用writeObject方法,将这个集合写到文件中。
5. 关闭序列化流
6. 创建反序列化流ObjectInputStream对象
7. 调用readObject方法,读取对象
8. 遍历读取到的集合
9. 关闭反序列化流
public class Demo05Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建集合保存Person
ArrayList<Person> list = new ArrayList<>();
//向集合中添加Person对象
list.add(new Person("张无忌", 12));
list.add(new Person("周芷若", 11));
list.add(new Person("赵敏", 10));
//创建序列化流ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10\\file07-test.txt"));
//调用writeObject方法,将这个集合写到文件中。
oos.writeObject(list);
//关闭序列化流
oos.close();
//创建反序列化流ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day10\\file07-test.txt"));
//调用readObject方法,读取对象
ArrayList<Person> list2 = (ArrayList<Person>)ois.readObject(); //把读取出来的对象强转成ARrayList然后赋值
//遍历集合
for (Person p : list2) {
System.out.println(p.getName() + "-" + p.getAge());
}
//释放资源
ois.close();
}
}
5、 Serializable这个接口中没有任何的方法,这个接口的作用是做为一个标记。
只有实现这个接口,这个类的对象才能够被序列化。
如何给类固定分配一个版本号?
提供一个成员变量即可,这个成员变量叫做serialVersionUID。 并且使用private static final修饰
并且这个成员变量是long类型。
public class Person implements Serializable{
//此时这个类的版本号永远是1,不管对这个类如何修改,这个类的版本号永远不会变永远是1.
private static final long serialVersionUID = 1L;
private String name;
private /*static*/ /*transient*/ int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
四、打印流
1、打印流
PrintStream: 字节打印流
PrintWriter: 字符打印流
打印流的特点:
1. 输出内容相对来说比较简单。
2. 这个流只有输出,没有输入。
PrintStream 构造方法:
PrintStream(File file): 参数传递File对象
PrintStream(OutputStream out): 传递一个字节输出流
PrintStream(String fileName): 传递一个字符串。
写数据的方法:
print: 输出但是不换行
println:输出并直接换行
write: 可以写字节数组,写字节数组的一部分,写字节
print和write的区别: 如果参数传递数字write方法会查询ASCII码表写入对应的字符。print方法会原样输出。
public class Demo01PrintStream {
public static void main(String[] args) throws IOException {
//创建一个打印流对象
PrintStream ps = new PrintStream("day10\\file08.txt");
//调用print方法,向文件写数据
//ps.print("你好");
//ps.print("我好");
//ps.println("你好");
//ps.println("我好");
//ps.write("你好".getBytes());
//ps.println(100); //100
ps.write(100);//d
//释放资源
ps.close();
}
}
public class Demo02PrintStreamTest {
public static void main(String[] args) throws FileNotFoundException {
//创建一个打印流
PrintStream ps = new PrintStream("day10\\file09.txt");
//使用System.setOut改变打印流的流向
System.setOut(ps); //此时通过System.out.println打印的内容都会输出到file09.txt中
System.out.println("你好");
}
}