IO 输入输出(Input/Output)流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输IO流就是用来处理设备间数据传输问题的,常见的应用有:文件复制、文件上传、文件下载。一般来说,我们说的IO流的分类是按照数据类型来分的。如果数据通过Windows自带的记事本软件打开,还可以读懂里面的内容,就使用字符流;否则使用字节流。如果不知道采用哪种类型的流,就使用字节流。
IO流分类
| 分类标准 | 具体内容 |
|---|---|
| 按照数据的流向 | 输入流:读数据 输出流:写数据 |
| 按照数据类型来分 | 字节流(字节输入流;字节输出流) 字符流(字符输入流;字符输出流) |
InputStream类在java.io包中,使用需要导包;public abstract class InputStream extends Object implements Closeable 是个抽象类,继承自Object类,实现了Closeable接口这个类表示输入字节流的所有类的超类(父类)。它的直接子类都是以InputStream结尾的。OutputStream类在java.io包中,使用需要导包;public abstract class OutputStream extends Object implements Closeable,Flushable 是个抽象类,继承自Object类,实现了Closeable,Flushable类这个类表示字节输入流的所有类的超类。它的直接子类都是以OutputStream结尾的。 字节流写数据
使用FileOutputStream:文件输出流用于将数据写入File
构造方法:FileOutputStream(String name):创建文件输出流 以指定的名称写入文件
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\fos.txt");
做了三件事情:
①调用系统功能创建了文件
②创建了字节输出流对象
③让字节输出流对象指向创建好的文件
使用字节输出流写数据的步骤:
1 创建字节输出流对象(调用系统功能创建了文件、创建字节输出流对象、让字节输出流对象指向文件) FileOutputStream fos = new FileOutputStream(path) 2 调用字节输出流对象的写数据方法 fos.write; 3 释放资源(关闭此文件输出流并释放与此相关联的任何系统资源) fos.close();
代码:
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\fos.txt");
// void write(int b):将指定的字节写入此文件输出流
fos.write(97);
// 这里需要抛出异常,之前FileOutputStream创建字节流对象时抛出的异常是 throws FileNotFoundException ;当write方法抛出异常 throws IOException 后,上述异常就没有了,因为throws FileNotFoundException 是 此异常的子类异常。
// fos.write(97); 写入文件后,文件显示是a 因为虽然低层写入是97,但是使用记事本打开之后会显示字符。
// 要想显示97,需要分别输入9 和 7
fos.write(57);
fos.write(55);
// 这里书写的是 字符 9 和 7
// void close():关闭此文件输出流并释放与此流相关联的任何系统资源。
fos.close();
}
}
字节流写数据的方式
| 方法名 | 说明 |
|---|---|
| void write(int b) | 将指定的字节写入此文件输出流 依次写入一个字节数据 |
| void write(byte[] b) | 将b.length字节从指定的字节数据写入此文件输出流 一次写一个字节数组数据 |
| void write(byte[] b,int off,int len) | 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,off也就是索引 一次写入一个字节数组的部分数据 |
案例涉及一个String的方法:String对象.getByte() 返回字符串对应的字节数据。
案例:
public class FileOutputDemo1 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream(".\fos.txt");
// 实际上 采用上述形式 类FileOutputStream底层也是进行了new File操作
// FileOutputStream fos1 = new FileOutputStream(new File(".\fos.txt"));
// void write(int a):将指定的字节写入此文件输出流
// void write(byte[] b):将b.length字节从指定的字节数组写入此文件输出流
byte[] bys = {101,100,99,98,97};
// byte[] getBytes():返回字符串对应的字节数组 这个方法是String的
byte[] bys1 = "ab".getBytes();
// fos.write(bys);
// fos.write(bys1);
fos.write(bys, 1, 2);
}
}
字节流写数据的两个小问题
字节流写数据如何实现换行?
不同操作系统的换行符不同。
window是rn,linux是n,mac是r
使用FileOutputStream的另一个构造方法
public FileOutputStream( String name,boolean append)创建文件输出流以指定的名称写入文件。如果第二个参数为true,则字节将写入文件的末尾而不是开头。
案例:
public class FileOutputDemo2 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream(".\fos.txt",true);
for(int i = 0 ; i < 10;i++){
fos.write("world".getBytes());
// 换行可以采用n的形式
fos.write("n".getBytes());
// 视频中讲解的是 windows系统使用n不行,idea软件打开是有换行的,但是系统本身的记事本打开没有换行;但是自己电脑打开已经换行了
}
fos.close();
}
}
字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有清除操作。比如说IO流中的释放操作
特点:被finally控制的语句一定会执行,除非JVM退出
finally和try…catch配合使用:
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
执行所有清除操作;
}
案例:
public class FileOutputDemo3 {
public static void main(String[] args){
// 这里报错的原因是 有异常没有被处理。
// 之前都是通过throws 处理异常的,本次通过try..catch处理。
// 为了确保在任何情况下 都实现资源释放,也就是字节流输出流对象.close方法
// 这种形式,当fos = new FileOutputStream(".\fos.txt"); 采用已存在的文件不会有问题,当采用的路径是不存在的文件时 会报错
FileOutputStream fos = null;
try{
fos = new FileOutputStream("Z:\fos.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
// **因为fos有问题是空,则这里的就是null null调用close会出错 null调用close是空指针异常。NullPointerException
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// **报错:FileNotFoundException 系统找不到指定路径 说明 fos = new FileOutputStream("Z:\fos.txt");这里路径有问题。
}
}
字节流读数据(一次读一个字节数据)
FileInputStream类public class FileInputStream extends InputStream 继承自InputStream类意思是:从文件中获取输入字节。构造方法FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name 命名
使用字节输入流读数据的步骤:
1 创建字节流读数据对象
FileInputStream fis = new FileInputStream(路径)
2 字节流读数据对象调用读数据方法
对象.read
int by ;
while((by = fis.read()) != -1){
System.Output.println((char)by);
}
3 释放内存空间
对象.close
fis.close();
字节流写数据方法
| 方法名 | 说明 |
|---|---|
| int read(int b) | 从该输入流读取一个字节的数据 返回值是实际读取字节的长度 |
| int read (byte[] b) | 从该输入流读取最多b.length个字节的数据到一个字节数组 返回值是实际读取字节的长度 |
需求:把文件fos.txt中的内容读取出来在控制台输出
案例:
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
// 创建字节输入流对象
FileInputStream fis = new FileInputStream(".\fos.txt");
// 调用字节输入流对象的读数据方法
// int read():从该输入流读取一个字节的数据
// 要想读取整个文件内容,可以使用循环,但是循环的结束条件是什么?如果达到文件的尾部,获取的是-1
//优化上面的程序
int by;
while((by = fis.read()) != -1){
System.out.println((char)by);
}
// 释放资源
fis.close();
}
}
案例:字节流复制文本文件
需求:把“E:222xxx.txt”复制到模块目录下的"xxx.txt"
public class InputOutputDemo {
public static void main(String[] args) throws IOException {
// 创建字节输入流对象
FileInputStream fis = new FileInputStream("E:\222\test.txt");
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\test.txt");
int by;
while((by = fis.read()) != -1){
fos.write(by);
}
// 释放内存空间
fos.close();
fis.close();
}
}
案例:字节流读数据(一次读一个字节数组数据)
需求:把文件fos.txt中的内容读取出来在控制台输出
涉及内容:String类中的方法
| 方法名 | 说明 |
|---|---|
| String (byte[] byte) | 把字节数组转化为字符串 |
| String(btye[] byte,int offset,int len) | 把字节数组从offset索引开始转换len长度的字符串 |
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream(".\fos.txt");
// 调用字节输入流对象的读数据方式
// int read(byte[] b) :从该输入数据流读取最多b.length个字节的数据到一个字节数组
// byte[] bys = new byte[5];
// 改进:
byte[] bys = new byte[1024];//1024及其整数倍
int len;
while((len = fis.read(bys)) != -1){
System.out.println(new String(bys,0,len));
}
// 释放空间
fis.close();
}
}
案例:复制图片
需求:把“E:xxx.jpg”复制到模块目录下的“xxx.jpg”
public class Demo1 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("E:\222\4.jpg");
FileOutputStream fos = new FileOutputStream(".\4.jpg");
byte[] bys = new byte[1024];
int len;
while((len = fis.read(bys)) != -1){
fos.write(bys,0,len);
}
fos.close();
fis.close();
}
}
字节缓冲流
BufferedOutputStream在java.io包下,使用需要导包的;它的父亲是OutputStream,说明它是字节输出流public class BufferedOutputStream extends FilterOutputStream,说明这个类继承自FilterOutputStream该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用,这句话的意思是:FileOutputStream写字节会调用底层系统;而BufferedOutputStream可以向FileOutputStream这样的输出流写字节BufferedInputStream在java.io包下,使用需要导包;它的祖先是InputStream,说明它是字节输入流创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
BufferedInputStream和BufferOutputStream的构造方法
| 方法名 | 说明 |
|---|---|
| BufferedInputStream(InputStream in) | 字节缓冲输入流 |
| BufferedOutputStream(OutputStream out) | 字节缓冲输出流 |
案例:
public class BufferedStreamDemo1 {
public static void main(String[] args) throws IOException {
//创建字节缓冲输出流
// 字节缓冲输入流:BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(".\bos.txt"));
// 一次读取一个字节数据
// 一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
// read(byte[] b):从输入字节流中最多读取b.length长度的字节数据到一个字节数组
while((len = bis.read(bys)) != -1){
System.out.print(new String(bys,0,len));
}
//释放资源
bis.close();
}
}
案例:复制视频
四种方式实现复制视频,并记录每种方式复制视频的时间
1 方式一:基本字节流一次读写一个字节
FileInputStream fis = new FileInputStream(源地址);
FileOutputStream fos = new FileOutputStream(目的地址);
int by;
while((by = fis.read()) != -1){
fos.write(by);
}
fis.close();
fos.close();
2 方式二:基本字节流一次读写一个字节数组
FileInputStream fis = new FileInputStream(源地址);
FileOutPutStream fos = new FileOutputStream(目的地址);
byte[] bys = new byte[1024];
int len;
while((len = fis.read(bys)) != -1){
fos.write(bys,0,len);
}
fis.close();
fos.close();
3 方式三:字节缓冲流一次读写一个字节
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(源地址));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream (目的地址));
int by;
while((by = bis.read()) != -1){
bos.write((char)by);
}
bos.close();
bis.close();
4 方式四:字节缓冲流一次读写一个字节数组
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(源地址));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream (目的地址));
byte[] bys = new byte[1024];
int len;
while((len = bis.read(bys)) != -1){
bos.write(bys,0,len);
}
fis.close();
fos.close();
案例:
public class Demo1 {
public static void main(String[] args) throws IOException {
// 记录开始时间
long startTime = System.currentTimeMillis();
// 复制视频
// method1(); // 共耗时:134811毫秒
// method2();//共耗时:326毫秒
// method3();//共耗时:682毫秒
method4();//共耗时:96毫秒
// 记录结束时间
long endTime = System.currentTimeMillis();
System.out.println("共耗时:" + (endTime - startTime) + "毫秒");
}
// 基本字节流一次读写一个字节
public static void method1() throws IOException {
FileInputStream fis = new FileInputStream("E:\222\xhj.mp4");
FileOutputStream fos = new FileOutputStream(".\xhj.mp4");
int by;
while((by = fis.read()) != -1){
fos.write(by);
}
fis.close();
fos.close();
}
// 基本字节流一次读写一个字节数组
public static void method2() throws IOException {
FileInputStream fis = new FileInputStream("E:\222\xhj.mp4");
FileOutputStream fos = new FileOutputStream(".\xhj.mp4");
byte[] bys = new byte[1024];
int len;
while((len = fis.read(bys)) != -1){
fos.write(bys,0,len);
}
fis.close();
fos.close();
}
//字节缓冲流一次读写一个字节
public static void method3() throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\222\xhj.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(".\xhj.mp4"));
int by;
while((by = bis.read()) != -1){
bos.write(by);
}
bis.close();
bos.close();
}
//字节缓冲流一次读写一个字节数组
public static void method4() throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\222\xhj.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(".\xhj.mp4"));
byte[] bys = new byte[1024];
int len;
while((len = bis.read(bys)) != -1){
bos.write(bys, 0, len);
}
bis.close();
bos.close();
}
}



