缓冲流
缓冲流也叫高效流,是对四个基本的FileXXX流的增强,按照数据类型分类:
字节缓冲流:BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader,BufferedWritter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过对缓冲取=区读写,减少系统IO次数,从而提高读写效率
字节缓冲流
构造方法:
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
参数:
OutputStream out:字节输出流
我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
package FileBufferDemo;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class BufferInputStream {
public static void main(String[] args) throws IOException {
//1、创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:\\a.txt");
//2、创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象效率
BufferedInputStream bos = new BufferedInputStream(fis);
//3、使用BufferedInputStream对象中方法read,读取文件
/*int len=0;
while ((len =bos.read())!=-1){
System.out.println(len);
}*/
byte[] bytes =new byte[1024];
int len =0;
while ((len=bos.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
bos.close();
}
}
字符缓冲流
构造方法
public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。
特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
BufferedReader: public String readLine() : 读一行文字。
BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号。
package FileBufferDemo;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferOutputStream {
public static void main(String[] args) throws IOException {
//1、创建FileOutputStream对象,构造方法中绑定要输出的目的地
FileOutputStream fos = new FileOutputStream("D://a.txt");
//2、创建BufferefOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
BufferedOutputStream bos =new BufferedOutputStream(fos);
//3、使用BufferedOutputStream对象中的方法write,把数据写入到内存缓冲区中
bos.write("我把数据写入到内存缓冲区".getBytes());
bos.flush();
bos.close();
}
}
package FileBufferDemo;
import java.io.*;
public class BufferedReaderAndWriter {
public static void main(String[] args) throws IOException {
//BufferedWriter
//1、创建字符缓冲流输出流对象,构造方法中传递字符输出流
//BufferedWriter bw= new BufferedWriter(new FileWriter("D:\\a.txt"));
//2、调用字符输出流中的write方法,把数据写入到内存缓冲区
/* for (int i = 0; i < 4; i++) {
bw.write("传智播客");
//void newLine() 写入一个行分隔符,会根据不同的操作系统,获取不同的行分隔符
bw.newLine();//等效于bd.write(“\r\n”)
}
bw.flush();
bw.close();*/
//BufferedReader
//1、创建字符缓冲输入流对象,构造方法中传递字符输入流
BufferedReader bd= new BufferedReader(new FileReader("D://a.txt"));
//2.使用字符缓冲输入流对象中的方法read/readLine读取文本
/*String readLine()//读取一个文本行 读取一行数据
行的终止符号:通过下列字符之一即可认为某行已终止:
换行(“\n”)、回车(“\n")或回车后直接跟着换行(“\r\n”)
返回值:
包含该行内容的字符串,不包含任何终止符,如果已达到流末尾,则返回null
*/
String line;
while ((line=bd.readLine())!=null){
System.out.println(line);
}
}
}
package FileBufferDemo;
/*练习:
对文本的内容进行排序,按照(1,2,3....)顺序排序
分析:
1、创建一个HashMap集合对象,可以:存储每行文本的序号(1.2.3,...),value存储每行的文本
2、创建字符缓冲输入流对象,构造方法中绑定字符输入流
3、创建字符缓冲输出流对象,构造方法中绑定字符输出流
4、使用字符缓冲输入流中的方法readLine,逐行读取文本
5、把读取的文本进行切割,获取行中的序号和文本内容
6、把切割好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3...)
7、遍历HashMap集合,获取每一个键值对
8、把每一个键值对,拼接成为一个文本行
9、把拼接好的文本,使用字符缓冲输出流中的方法write,写入到文本中
10、释放资源
*/
import java.io.*;
import java.util.HashMap;
public class BufferedExerciseDemo {
public static void main(String[] args) throws IOException {
HashMap<String,String> map = new HashMap<>();
BufferedReader br = new BufferedReader(new FileReader("D:\\abc.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\B.TXT"));
String line;
while ((line=br.readLine())!=null){
String[] arr=line.split("\\.");
map.put(arr[0],arr[1]);
}
for(String key:map.keySet()){
String value =map.get(key);
line=key+"."+value;
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
}
}
package FileBufferDemo;
/*
文件复制练习二:
明确:
数据源:D://me.jpg
数据目的地:C://me.jpg
文件复制的步骤:
1、创建一个字节缓冲输入流对象,构造方法中传递字节输入流
2、创建一个字节缓冲输出流对象,构造方法中传递字节输出流
3、使用字节缓冲输入流对象中的方法read读取文件
4、使用字节缓冲输出流对象中write方法,把读取的数据写入到内存缓冲区中
5、释放资源(会先把缓冲区中的数据刷新到文件中)
*/
import java.io.*;
public class BufferedCopyExercised {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
BufferedInputStream br =new BufferedInputStream(new FileInputStream("D:\\me.jpg"));
BufferedOutputStream bw =new BufferedOutputStream(new FileOutputStream("F:\\me.jpg"));
byte[] bytes =new byte[1024];
int len=0;
while ((len=br.read(bytes))!=-1){
bw.write(bytes,0,len);
}
bw.flush();
bw.close();
long end =System.currentTimeMillis();
System.out.println("总共花费:"+(end=start));
}
}
转换流
字符编码和字符集
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制
数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照
某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符
号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。
字符集
字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符
号、数字等。
计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符
集有ASCII字符集、GBK字符集、Unicode字符集等。
在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8 编码,所以没有任何
问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
import sun.audio.NativeAudioStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class FileBianMaDemo {
public static void main(String[] args) throws IOException {
//定义文件路径,文件UTF-8编码
String fileName ="D:\\file_gbk.txt";
//创建流对象,默认为UTF-8编码
InputStreamReader ie=new InputStreamReader(new FileInputStream(fileName));
//创建流对象,指定GBK编码
InputStreamReader ie1 =new InputStreamReader(new FileInputStream(fileName),"GBK");
//定义变量,保存字符
int len =0;
while ((len =ie1.read())!=-1){
System.out.println((char)len);
}
ie.close();
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class FileBianMaDemo1 {
public static void main(String[] args) throws IOException {
//定义文件路径
String fileName = "D:\\b.txt";
//创建流对象,默认为UTF8编码
OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream(fileName));
//创建流对象,指定GBK编码
OutputStreamWriter ow1 = new OutputStreamWriter(new FileOutputStream("D:\\c.txt"),"GBK");
//写出数据
ow.write("你好");//保存为6个字节
ow1.write("你好");//保存为4个字节
ow1.flush();
ow1.close();
}
}
/*练习:1、指定GBK编码转换流,读取文本文件
2、使用UTF-8编码转换流,写出文本文件
*/
import java.io.*;
public class FileBianMaDemo02 {
public static void main(String[] args) throws IOException {
String srcFile ="D:\\file_gbk.txt";
String dstFile ="D:\\file_utf8.txt";
//创建流对象
//2.1转换输入流,指定gbk编码
InputStreamReader isr= new InputStreamReader(new FileInputStream(srcFile),"GBK");
//2.2转换输出流,默认utf8编码
OutputStreamWriter dst = new OutputStreamWriter(new FileOutputStream(dstFile));
//3、读写数据
//3.1定义数组
char[] chars =new char[1024];
int len =0;
while ((len=isr.read(chars))!=-1){
dst.write(chars,0,len);
}
isr.close();
dst.close();
}
}
序列化
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的
类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中
存储的数据信息,都可以用来在内存中创建对象。看图理解序列化:
package SerializableDemo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
//1、创建ObjectOutputStream对象,构造方法中传递字节输出流
ObjectOutputStream oo= new ObjectOutputStream(new FileOutputStream("D:\\d.txt"));
//2、使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
oo.writeObject(new Person("小美女",19));
//3、释放资源
oo.close();
}
}
package SerializableDemo;
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private 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;
}
}
package SerializableDemo;
import java.io.*;
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1、创建ObjectOutputStream对象,构造方法中传递字节输出流
ObjectInputStream oo= new ObjectInputStream(new FileInputStream("D:\\d.txt"));
//2、使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
Object o = oo.readObject();
//3、释放资源
oo.close();
//4、使用读取出来的对象打印
System.out.println(o);
Person person=(Person)o;
System.out.println(((Person) o).getName()+":"+((Person) o).getAge());
}
}
ps:
当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操
作也会失败,抛出一个InvalidClassException 异常。发生这个异常的原因如下:
该类的序列版本号与从流中读取的类描述符的版本号不匹配
该类包含未知数据类型
该类没有可访问的无参数构造方法
Serializable 接口给需要序列化的类:
eg:
public class Person implements Serializable {}
package SerializableDemo;
/*
练习:序列化集合
当我们想在多个对象中保存集合的时候,可以把多个对象存储到一个集合中
对集合进行序列化和反序列化
分析:
1、定义一个存储person对象的ArrayList集合
2、往集合中存储person对象
3、创建一个序列化流ObjectOutputStream对象
4、使用ObjectOutputStream对象writeObject,对集合进行序列化
5、创建一个反系列化流InputStream对象
6、使用ObjecyInputStream对象readObject,读取文件中保存的集合
7、把Object类集合转换为ArrayList类型
8、遍历ArrayList集合
9、释放资源
*/
import java.io.*;
import java.util.ArrayList;
public class ObjectSerializableExercise {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ArrayList<Person> list =new ArrayList<>();
list.add(new Person("张三",18));
list.add(new Person("李四",19));
list.add(new Person("王五",20));
ObjectOutputStream oo =new ObjectOutputStream(new FileOutputStream("D:\\e.txt"));
oo.writeObject(list);
ObjectInputStream oi = new ObjectInputStream(new FileInputStream("D:\\e.txt"));
Object O =oi.readObject();
ArrayList<Person> list1 =(ArrayList<Person>)O;
for (Person p:list1){
System.out.println(p.getName()+":"+p.getAge());
}
oo.close();
oi.close();
}
}
打印流
平时我们在控制台打印输出,是调用print 方法和println 方法完成的,这两个方法都来自于
java.io.PrintStream 类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class PrintStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
//创建打印流PrintStream对象,构造方法中绑定要输出的目的地
PrintStream ps = new PrintStream("D:\\f.txt");
//如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表97->a
//ps.write(97);
//如果使用自己特有的方法print/println方法写数据,写的数据原样输出97
ps.println(97);
ps.println(true);
ps.close();
}
}
/*可以改变输出语句目的地(打印流流向)
输出语句默认在控制太输出
使用System.setOut方法改变输出语句目的地 改为参数中传递的打印流的目的地
static void setOut(PrintStream out)
*/
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class PrintStreamDemo01 {
public static void main(String[] args) throws FileNotFoundException {
int a=1;
int b=2;
System.out.println("我是在系统输出");
//创建打印流 指定文件名称
PrintStream ps = new PrintStream("D:\\e.txt");
//设置系统的打印流流向,输出到e.txt
System.setOut(ps);
System.out.println(97);
}
}