推荐视频学习连接
(间断更新,QVQ学业繁重,课上用到IO流的次数太少了,我们老师5分钟给我们讲完,学习视频8个小时T_T,但愿我的笔记对你有用)
在Java程序中,对于数据的输入(input)/输出(output)操作以"流”(stream) 方式进行; Java提供了各种各样的“流"类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。
Java的流类型-般位于java.io包中。
数据源data source ,提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO 设备。
流是一个抽象、动态的概念,是一连串连续动态的数据集合。
按流的方向分类:
输出流:数据流向是数据源到程序(以InputSream、Reader结尾的流)
输出流:数据流向是程序到目的地(以Outputstream、Writer结尾的流)
(注:输入输出流的划分是相对程序而言的,并不是相对数据源)
按处理的数据单元分类:
字节流:以字节为单位获取数据,命名以Stream结尾的流一般是字节流,顶级类是InputStream、OutStream
字符流:以字符为单位获取数据,命名以Reader/Writer结尾的流一般是字符流,顶级类Reader、Writer。
**按处理对象不同分类:**
节点流:可以直接从数据源或目的地读写数据,如FileinputStream、FileReader等。
处理流:不直接连接到数据源和目的地,是“处理流的流”。通过对其他流的处理提高程序的性能如,BufferedInputStream、BufferedReader等。处理流也叫包装流。
(注:节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或程序的灵活性)
(数据流是必不可少,处理流只是包装,能提高性能,但可以没有)
字节流
(1)inputStream和OutStream是java语言中最基本的两个输入输出类,其他所有字节输入输出流都继承自这两个基类
(2)这两类都是抽象类,不能创建他们的实例,自能使用他们的子类
(3)FilerInputStream和FilerOutputStream是所有包装流的父类
字符流
(1)java语言中最基本的两个字符输入输出类,Reader和Writer
(2)其他所有字符输入输出类都继承自这两个基类。
(3)这两个都是抽象类,不能创建他们的实例,只能用他们的子类
File类用来代表文件和文件夹。主要作用有两个:获取文件夹的属性;实现对文件、文件夹的创建和删除。文件夹:file folder 目录:directory
常用的方法:
import java.io.File;
import java.util.Date;
public class Demo02File {
public static void main(String[] args) {
File file = new File("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");//绝对路径,根路径
System.out.println(file.getName());//返回文件名
System.out.println(file.length());//字节长度
System.out.println(file.exists());//是否存在
System.out.println(file.canRead());//是否可读
System.out.println(file.canWrite());//是否可写
System.out.println(file.canExecute());//是否可执行
System.out.println(file.isFile());//是文件吗
System.out.println(file.isDirectory());//是目录(文件夹)吗
File file1 = new File("D:\\steam");//打开一个文件夹
File[] files = file1.listFiles();
System.out.println(files.length);//返回steam文件夹中文件和文件夹的数量和
for (File i : files) {
//获得steam文件夹中文件和为文件夹的名称和最后修改时间
System.out.println(i.getName()+"\t"+new Date(i.lastModified()).toLocaleString());
}
}
}
创建、删除文件夹
import java.io.File;
import java.io.IOException;
public class Demo02NewFile {
public static void main(String[] args) throws IOException {
//创建一个File对象指向一个文件
File file = new File("D://first.txt");
//如果这个文件夹存在,删除;不存在,创建。
if(file.exists()){
file.delete();
}else{
file.createNewFile();
}
}
}
但是File不能对文件的内容进行 操作,内容操作要使用IO流
(1)FileOutputStream 和FileInputStream是字节流,是节点流,数据源和目的地是文件夹。
(2)复制文件需要分别创建一个输入输出流完成文件读写
(3)需要创建一个中转站,借助循环和中转站完成复制
(4)使用完毕一定要关闭,这和垃圾回收没用关系(一定要关闭QVQ,我在第二次使用这个方法输入14M的音乐文件,输出了1.3G,而且输出的文件打开了把我电脑弄死机了)
复制一个txt文档
import java.io.*;
public class Demo03Copy {
public static void main(String[] args) throws IOException {
//1.创建输入流和输出流
File file1 = new File("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
File file2 = new File("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt");
FileInputStream is = new FileInputStream(file1);
FileOutputStream os = new FileOutputStream(file2,true);//append true追加(追加是指到指定的文件中) false 覆盖(把指定的文件完全覆盖掉)
//2.使用输入流和输出流完成文件复制
int n;//定义一个中转站,就是一个字节
n = is.read();
while(n != -1){ //n == -1 读到了文件末尾
//写一个字节
os.write(n);
n = is.read();
}
//3.完毕关闭输入、输出流
is.close();
os.close();
}
}
缺点:中转站太小,速度慢,效率低;复制更大文件时效果更明显;可以将中转站由一个字节变成一个字节数组,减少读写硬盘的次数。
复制一个MP4文件(一定要关闭IO流)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo04CopyBigFile {
public static void main(String[] args) throws IOException {
FileInputStream is = new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\東山奈央 - 月がきれい.mp3");
FileOutputStream os = new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\東山奈央 - 月がきれい1.mp3",true);
byte[] bytes = new byte[1024];//定义一个字节数组,是一个中转站
int len = is.read(bytes);//读文件的内容放到字节数组中,返回读取的字节数
while(len != -1){
os.write(bytes,0,len);
len = is.read(bytes);
}
//完毕关闭输入输出流
os.close();
is.close();
}
}
异常处理
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo05FileException {
public static void main(String[] args) {
FileInputStream is = null;
FileOutputStream os = null;
try {
is = new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
os = new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt",true);
int len;
len = is.read();
while(len != -1){
os.write(len);
len = is.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(is != null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
分析:创建流、使用流要使用一次try-catch语句,关闭流要分开进行异常处理
Java7异常处理新特性:try-with-resource:不用显示的进行资源的关闭,子要将资源的实例化对象放入try后面的()中,作用范围是当前的try语句,执行完毕后会自动进行关闭,可省略finally语句,更加简单实用
关于java9中异常处理新变化:try之前定义好对象,try()括号中引入创建好的对象。如果多个对象,使用;分割。如果try之前的定义的对象对抛出异常,就不推荐使用该方式,因为需要在方法签名中throws异常
字符流复制txt文件
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo06charFile {
public static void main(String[] args) throws IOException {
//1.创建输入流和输出流
FileReader fr = new FileReader("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
FileWriter fw = new FileWriter("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt");
//2.1使用输入流和输出流复制文件
int n;//定义中转站
n =fr.read();
while(n != -1){
fw.write(n);
System.out.println((char) n);
n = fr.read();
}
// 3.关闭输入流和输出流
fr.close();
fw.close();
}
}
字符流复制大文件
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo07CharBigFilr {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
FileWriter fw = new FileWriter("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt");
char[] cbuf = new char[1024];//定义中转站,一个字符数组
int len = fr.read(cbuf);
while(len != -1){
//写一个字符数组的内容到文件
fw.write(cbuf,0,len);
//输出到控制台
System.out.println(len);
System.out.println(cbuf);
len = fr.read(cbuf);
}
fr.close();
fw.close();
}
}
(1)使用字节流可以读写任意类型的文件
(2)使用字符流只可以读写文本文件(使用记事本可以打开的文件) #doc文件不是文本文件
(3)使用字符流的好处;处理非英文字符(汉字之类)方便
(4)其实只有字节流,没有字符流;字符流的底层还是字节流
(1)使用缓冲流可以提高读写速度
(2)关闭高层流即可,无需关闭底层流(关闭高层流其实就是再关闭底层流)
(3)缓冲流为什么可以提高查询的速度(因为输入输出缓冲区,大大减少了读写硬盘的次数)
(4)如何刷新输出缓冲区(将缓冲区的最新数据写入到文件中)
方法一:bos.close(); 先刷新,再关闭。
方法二:直接调用 bos.flush();
方法三:缓冲区满,自动刷新
import java.io.*;
public class Demo08Buffered {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt"));
byte[] bytes = new byte[1024];
int len =bis.read(bytes);
while(len != -1){
bos.write(bytes,0,len);
System.out.println(len);
len = bis.read();
}
bis.close();
bos.close();
}
}
之前使用文件流、缓冲流读取文件只能按照字节、数组方式读取,最方便的也是按行读取,能否很方便的实现对各种基本类型和引用类型数据的读写,并保留其本身的类型。数据流DataInputStream和DataOutputStream和对象流ObjectInputStream和ObjectOutputStream可以解决这个问题,最大的优势就是提供了方便操作各种数据类型的方法,直接调用,简单方便。
注意
●只有字节流,没有字符流
●都是处理流,不是节点流
●数据流只能操作基本数据类型和字符串,对象流还可以操作对象
●写入的是二进制数据,无法直接通过记事本等查看
●写入的数据需要使用对应的输入流来读取
//数据流最大的优点就是方便
public class Demo09DataStream {
public static void main(String[] args) {
try {
read();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void read() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
DataInputStream dis = new DataInputStream(bis);
System.out.println(dis.readInt());
System.out.println(dis.readChar());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
}
public static void write() throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(33);
dos.writeChar('d');
dos.writeDouble(1.35);
dos.writeBoolean(false);
dos.close();
}
}
import java.io.*;
import java.util.Date;
public class Demo10ObjectStream {
public static void main(String[] args) {
try {
// write();
read();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void read() throws IOException, ClassNotFoundException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
ObjectInputStream ois = new ObjectInputStream(bis);
System.out.println(ois.readInt());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
Date o = (Date)ois.readObject();
System.out.println(o);
ois.close();
}
public static void write() throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeInt(3424);
oos.writeChar('3');
oos.writeDouble(3.22);
oos.writeObject(new Date());
oos.close();
}
}
注意:使用对象流读写引用类型的数据,需要相应类实现Serializable接口,否则会提示异
常提、没有序列化,比如:java.io.NotSerializableException: com.bjsxt.entity .Student。
1.什么是序列化和反序列化?
序列化: Serialization 将对象的状态信息转换为可以存储或传输的形式的过程。
对象(内存------>字节数组字节序列(外存、网络)
反序列化: DeSerialization
字节数组字节序列(外存、网络) -------->对象(内存)
2.什么时候需要序列化和反序列化?
存储或传输比如存储到外存(硬盘)中传输到网络