第十二章 I/O
Input:输入
Output:输出
流的概念和作用
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
12.1 控制台下的I/O
输入:Scanner类,next方法
由控制台传输到程序中
输出:System.out.println();
由程序中传输到控制台
12.1.1 数据流
数据流就是数据传输的过程
根据流向可以分为两类
输入流:从程序外部流向程序
输入操作 read()
输出流:从程序流向程序外部
输出操作 writer()
根据数据传输单位分为两类
字节流:以字节为单位
字符流:以字符为单位
形成四种流 java.io包下有对流的实现
字节输入流:InputStream 表示字节输入流的所有类的超类
字节输出流:OutputStream 表示字节输出流的所有类的超类
字符输入流:Reader 用于读取字符流的抽象类
字符输出流:Writer 用于写入字符流的抽象类
流按照不同的功能又可进行分类
- 文件流:程序与文件之间进行数据传输
FileInputStream
FileOutputStream
FileReader
FileWriter
2)网络流:程序与网络之间进行数据传输
IO流的分类:
1、 根据处理的数据类型不同可以分为:字符流和字节流。
2、根据数据的流向不同可以分为:输入流和输出流。
什么情况下使用字符流:如果读写的都是字符数据,这时候我们就使用字符流。文本文件。
什么情况使用字节流: 读取到数据不需要经过编码或者解码的情况情况下这时候使用字节流。比如:图片数据、视频数据
字符流 = 字节流 + 编码(解码)
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
12.2 文件流
12.2.1 FileInputStream
将数据以字节的方式从文件读入到程序中
主要依赖于read()方法
12.2.2 FileOutputStream
将数据以字节的方式写入到文件中
12.2.3 FileReader
一个字符一个字符的读,直到读到了换行符
IO示例
public class IODemo {
@Test
public void testFileReader() {
FileReader fileReader = null;
try {
//FileReader fileReader = new FileReader("./src/1.txt");
//fileReader = new FileReader("src/com/situ/day13/2.txt");
fileReader = new FileReader("D://3.txt");
//fileReader = new FileReader("io.txt");
//public int read() 读取单个字符,如果已到达流的末尾,则返回 -1
int ch1 = fileReader.read();
System.out.println((char)ch1);//a
int ch2 = fileReader.read();
System.out.println((char)ch2);//b
int ch3 = fileReader.read();
System.out.println((char)ch3);//c
int ch4 = fileReader.read();
System.out.println(ch4);//-1
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testFileReader2() {
FileReader fileReader = null;
try {
fileReader = new FileReader("io.txt");
int ch = -1;
//while循环去读,直到ch的值等于-1,就退出循环
while ((ch = fileReader.read()) != -1) {
System.out.println((char)ch);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testFileReader3() {
FileReader fileReader = null;
try {
fileReader = new FileReader("io.txt");
//public int read(char[] cbuf)
//将字符读入数组
//返回:读取的字符数,如果已到达流的末尾,则返回 -1
char[] buffer = new char[20];
int length = 0;
while ((length = fileReader.read(buffer)) != -1) {
System.out.println(length);
System.out.println(Arrays.toString(buffer));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
12.2.4 FileWriter
写入一个空行
\n\r
public void fileCopy() {
FileReader fileReader = null;
FileWriter fileWriter = null;
try {
fileReader = new FileReader("io.txt");
fileWriter = new FileWriter("io_back.txt");
char[] buffer = new char[20];
int length = 0;
while ((length = fileReader.read(buffer)) != -1) {
System.out.println(length);
System.out.println(Arrays.toString(buffer));
//读出多少就写多少,最后一次读取的数据可能不够buffer数组长度的数据
fileWriter.write(buffer, 0, length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字节流
InputStream:FileInputStream
OutputStream: FileOutputStream
在代码中生成一些文件,一些图片
网络应用
public void fileInputStreamCopy() {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream("bd_logo.png");
fileOutputStream = new FileOutputStream("bd_logo_back.png");
byte[] buffer = new byte[1024];//字节数组
int length = 0;
while ((length = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
12.3 包装流/装饰流/增强流
功能增强
装饰者模式:Java23种设计模式中的一种
在不改变原来流的基础上,通过包装类对其功能进行增强
字符缓冲流
BufferedReader
BufferedWriter
对象流
直接把一个对象保存到流中
从流中读取一个对象
ObjectInputStream
ObjectOutputStream
ObjectInputStream、ObjectOutputStream
将对象写入文件的操作流ObjectOutputStream,称为序列化。
从流中读取对象的操作流程ObjectInputStream,称为反序列化。
java.io.NotSerializableException: com.situ.day13.Student
Serialize序列化
public class Student implements Serializable{
private Integer id;
private String name;
private Integer age;
}
public class ObjectIODemo {
@Test
public void testObjectOuputStream() {
// 3 Oracle 1 SqlServer 6Mysql
Student student=new Student(1,"张三zhangsan", 20);
ObjectOutputStream objectOutputStream=null;
FileOutputStream fileOutputStream=null;
try{
fileOutputStream=new FileOutputStream("student");
objectOutputStream=new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(student);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}finally{
if(objectOutputStream!=null) {
try{
objectOutputStream.close();
}catch(IOException e) {
e.printStackTrace();
}
}
if(fileOutputStream!=null) {
try{
fileOutputStream.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testObjectInputStream() {
ObjectInputStream objectInputStream=null;
FileInputStream fileInputStream=null;
try{
fileInputStream=new FileInputStream("student");
objectInputStream=new ObjectInputStream(fileInputStream);
Objectobject=objectInputStream.readObject();
Studentstudent= (Student)object;
System.out.println(student);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
}
一般情况下:先打开的后关闭,后打开的先关闭。
另一种情况:看依赖关系,如果流A依赖于流B,先关闭流A,再关闭流B。