一、IO流
输入输出流: I input : O output
1.IO分类:
按照方向分: 输入流 和输出流
输入流: 读操作
输出流: 写操作
按照IO管道大小: 字节流: 一个字节一个字节的读写: 万能流
字符流: 一个字符一个字符读写: 读写文本文件
按功能分:
节点流:用于直接操作目标设备的流
处理流:是对一个已存在的流的连接和封装,通过对数据的处理为程序提供更强大、灵活的读写功能。
2.IO流类结构图:
4个抽象父类
字节输入流: InputStream
字节输出流: OutputStream
字符输入流: Reader
字符输出流: Writer
输入流主要方法:
read() 读方法
close() 关闭
输出流主要方法:
write() 写方法
close() 关闭
编写步骤:
创建IO流对象
读/写操作
关闭资源
二、输入、输出流
1.节点流
(1)字节节点流(万能流)
1.FileInputStream
FileInputStream fis = null;
//1.构造方法
FileInputStream(File file)
通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj)
创建 FileInputStream通过使用文件描述符 fdObj ,其表示在文件系统中的现有连接到一个实际的文件。
FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
//第一个和第三个构造方法差不多,第一个适合方法调用,第三个平时少写一行代码
//2.应用
try {
//1.创建IO流对象
fis = new FileInputStream("d:/hello.txt");
//2.进行读写操作
int rs = -1;
while((rs=fis.read()) != -1){
System.out.println((char)rs);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//3.关闭
try {
if(fis != null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
字节一个个读取特别慢
try {
//1.创建IO流对象
fis = new FileInputStream("d:/hello.txt");
//2.进行读写操作
int rs = -1;
//一个中文占三个字节
byte[] b = new byte[5];
while((rs=fis.read(b)) != -1){
//read() 一下, 只读一个字节 编码 返回的读到内容编码
//read(byte[] b) 把读到字节缓存到byte数组中 返回的是 读到的字节长度
//System.out.print((char)rs);
//把byte[] 转换为字符串
System.out.println(rs);
//String(byte[], offset, len)
// 从byte[] 数组中指定offset下标开始, 读len个字节
String s = new String(b,0,rs);
System.out.println(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//3.关闭
try {
if(fis != null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.FileOutputStream
FileOutputStream fos = null; //1.构造方法 FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。 FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File对象表示的文件。 FileOutputStream(FileDescriptor fdObj) 创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。 FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。 FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。
//2. FileOutputStream往文件写入内容
FileOutputStream fos = null;
try {
//1.创建IO对象
fos = new FileOutputStream("d:/a.txt",true);
//2.写
String str = "\nhello world\n";
//需要把字符串转换为byte数组
byte[] bytes = str.getBytes();
fos.write(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//3.关闭
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)字符节点流(.txt、.java能用记事本打开的文件)
1.FileReader文件符输入流
FileReader fr = null;
try {
//1.创建IO流对象
fr = new FileReader("d:/hello.txt");
//2.进行读写操作
//int rs = fr.read();
int rs = -1;
while((rs = fr.read()) != -1){
System.out.println((char)rs);
}
} catch (
FileNotFoundException e) {
e.printStackTrace();
} catch (
IOException e) {
e.printStackTrace();
}finally{
//3.关闭
try {
if(fr != null){
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.FileWriter文件符输出流
FileWriter fw = null;
try {
//1.创建IO对象
fw = new FileWriter("d:/a.txt",true);
//2.写
String str = "\n你好 世界\n";
fw.write(str);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//3.关闭
if(fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.内存流
唯一一种从网络获取二进制数据的(意义不大、一般不存在内存里)
当输出流的目的和输入流的源是内存时,这样两端都是内存
1. ByteArrayInputStream把内存某个字节数组中数据读取出来
-
ByteArrayOutputStream把数据写到内存的字节数组中
ByteArrayOutputStream boas = null;
try {
boas = new ByteArrayOutputStream();
String str = "hello world";
//写操作
boas.write(str.getBytes());
//刷新
boas.flush();
//得到字节数组
byte[] b = boas.toByteArray();
String s = new String(b);
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}finally{
if(boas!=null){
try {
boas.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.缓冲流:(处理流)
不能直接接只能接到别的输入输出流
自带缓冲区、byte字节流、char[]字符流
1.BufferedReader
FileReader fr = null;
BufferedReader br = null;
try {
//创建一个节点流
fr = new FileReader("d:/hello.txt");
//创建处理流
br = new BufferedReader(fr);
//读取 读到文件末尾: 返回: null
// String line = br.readLine();
String line = null;
//readLine() 遇到一个换行符结束读
while((line=br.readLine()) != null){
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
2.BufferedWriter
缓存输出流有一个8kb的缓存区
1.满了就自动输出写到文件里
2.手动调用flush(),不管满没满立即写到文件里
3.close方法,关闭前刷新
//FileWriter fw = null;
FileOutputStream fos = null;
BufferedWriter bw = null;
OutputStreamWriter osw = null;
//fw = new FileWriter("d:/hello.txt",true);
fos = new FileOutputStream("d:/hello.txt",true);
osw = new OutputStreamWriter(fos);
bw = new BufferedWriter(osw);
bw.write("呵呵");
//换行
bw.newLine();
bw.write("嘿嘿");
//刷新缓冲区
//bw.flush();
//倒序关
bw.close();
osw.close();
fos.close();
4.转换流
把字节流转换为字符流
1.InputSteamReader()
2.OutputSteamWrite()
5.打印流
PrintSteam 只有输出流、打印输出流:额外提供了一个打印方法print、println
1.字节打印流
2.字符打印流 PrintWriter
两个构造方法
常用构造方法 PrintWriter(System.out); PrintWriter(System.out,true/false); 是否自动清除缓冲区
PrintWriter pw = null;
//打印到控制台
// pw = new PrintWriter(System.out);
pw = new PrintWriter("d:/test.txt");
//打印方法
pw.println("你好:");
pw.println("中国");
pw.println(true);
pw.println(new Object());
pw.close();
6.对象流
可以读写对象
ObjectInputStream: 对对象进行反序列化, 读取这个字节序列,反序列化成为一个java对象
常用构造方法 ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream。
ObjectOutputStream:对对象进行序列化, 把这个对象转换为字节序列, 写出去
ObjectInputStream,ObjectOutputStream 是处理流, 需要一个字节流
常用构造方法 ObjectOutputStream(OutputStream out) 创建一个写入指定的OutputStream的ObjectOutputStream。
常见错误:
1.JDK默认禁止序列化 对某个对象进行序列化, 需要对这个对象开启允许序列化
只要让这个类实现java.io.Serizalizable接口
public class Student implements Serializable {
2.已经读到文件末尾, 还在读,产生该异常
readObject() 没有一个特殊值,表示读到文件末尾
一个类一旦设置serialVersionUID, 后期不能随意改动
如果某个属性敏感的,不想参与序列化, 使用transient关键字修饰
//提供一个常量: serialVersionUID 序列化id 默认值1
//private static final long serialVersionUID = 1L;
//5191370656703224314L 序列化对象,使用序列化id:
// 修改5191370656703226666L 不一样
private static final long serialVersionUID = 5191370656703224314L;
private int id;
private String name;
private String sex;
private int age;
// transient: 修饰的属性,不会进行序列化,写入到文件中
private transient String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
/*
* 方便测试, 方便打印这个对象,输出的是对象属性值
*/
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Student").append('[')
.append("id=")
.append(id)
.append(",name=")
.append(name)
.append(",sex=")
.append(sex)
.append(",age=")
.append(age)
.append(",password=")
.append(password)
.append(']');
return sb.toString();
}
public Student(int id, String name, String sex, int age, String password) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.password = password;
}
public Student() {
}
序列化
A程序: 把这个对象使用输出流, 把这个对象写出去: 把这个对象打散成字节序列: 序列化:
为了能让对象进行保存,或者进行网络传输
B程序: 使用输入流, 读取这个对象: 把字节序列重新组装成一个java对象: 反序列化
示例:将Student对象保存至文件中(序列化)
//1.创建一个学生类对象
Student stu = new Student(1,"张三","男",21,"123456");
Student stu1 = new Student(2,"李四","男",21,"156");
Student stu2 = new Student(3,"王五","男",21,"1236");
//2.保存到文件中, 输出流, 使用ObjectOutputStream
ObjectOutputStream oos = null;
FileOutputStream fos = null;
// 从盘符开始, "d:/stu.txt" 绝对路径
// "stu.txt": 相对路径
try {
fos = new FileOutputStream("stu.txt");
oos = new ObjectOutputStream(fos);
//2.保存到文件中, writeObject(Object )
//写int类型的数据, 表示写了多少个对象
oos.writeInt(3);
oos.writeObject(stu);
oos.writeObject(stu1);
oos.writeObject(stu2);
oos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//倒序关
try{
if(oos != null){
oos.close();
}
if(fos != null){
fos.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
//3.读取这个文件, 获取这个对象
反序列化(读出来)
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("stu.txt");
ois = new ObjectInputStream(fis);
//读取对象 反序列化
//循环读取
//readObject()
Student stu = null;
/* while((stu =(Student)ois.readObject()) != null){
System.out.println(stu);
}*/
//读第一个数据 int
int count = ois.readInt();
for (int i = 0; i <count ; i++) {
stu =(Student)ois.readObject();
System.out.println(stu);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//倒序关
try{
if(ois != null){
ois.close();
}
if(fis != null){
fis.close();
}
}catch (IOException e){
e.printStackTrace();
}
}