javaIO流-字节流-字节缓冲流-

IO流

概述

  • IO 输入\输出(Input/Output)
  • 流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输
  • IO流就是用来处理设备间数据传输问题的,常见的应用有:文件复制、文件上传、文件下载。
  • 一般来说,我们说的IO流的分类是按照数据类型来分的。
  • 如果数据通过Windows自带的记事本软件打开,还可以读懂里面的内容,就使用字符流;否则使用字节流。如果不知道采用哪种类型的流,就使用字节流。

IO流分类

分类标准具体内容
按照数据的流向输入流:读数据
输出流:写数据
按照数据类型来分字节流(字节输入流;字节输出流)
字符流(字符输入流;字符输出流)

字节流

概述

说明字节输入流字节输出流
名称InputStream类OutputStream类
所属包java.io包,需要导包java.io包,需要导包
类声明public abstract class InputStream extends Object implements Closeable 是个抽象类,继承自Object类,实现了Closeable接口public abstract class OutputStream extends Object implements Closeable,Flushable 是个抽象类,继承自Object类,实现了Closeable,Flushable类
表示表示输入字节流的所有类的超类(父类)表示输出字节流的所有类的超类
子类特点都是以InputStream结尾的都是以OutputStream结尾的

字节流写数据FileOutputStream

使用FileOutputStream对象:文件输出流用于将数据写入File

构造方法

方法名说明
FileOutputStream(String name)创建文件输出流 以指定的名称将数据写入文件(name路径)
public FileOutputStream( String name,boolean append)创建文件输出流以指定的名称写入文件。
如果第二个参数为true,则字节将写入文件的末尾而不是开头。
// 创建字节输出流对象
        FileOutputStream fos = new FileOutputStream(".\\fos.txt");
做了三件事情:
①调用系统功能创建了文件
②创建了字节输出流对象
③让字节输出流对象指向创建好的文件

使用字节输出流写数据的步骤:

1 创建字节输出流对象(调用系统功能创建了文件、创建字节输出流对象、让字节输出流对象指向文件)
	FileOutputStream fos = new FileOutputStream(path)
2 调用字节输出流对象的写数据方法
	fos.write();
3 释放资源(关闭此文件输出流并释放与此相关联的任何系统资源)
	fos.close();

代码:

// 35-FileOutputStreamDemo
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();
    }
}

字节流写数据的方法write(参数是 int 或 byte[])

方法名说明
void write(int b)将指定的字节写入此文件输出流
依次写入一个字节数据
void write(byte[] b)将b.length字节从指定的字节数据写入此文件输出流
一次写一个字节数组数据
void write(byte[] b,int off,int len)将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,off也就是索引
一次写入一个字节数组的部分数据

案例涉及一个String的方法:String对象.getByte() 返回字符串对应的字节数据。

案例:

// 35-FileOutputDemo1
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"));
        /*
        this(name != null ? new File(name) : null, false);
    */

		# //void write(int a):将指定的字节写入此文件输出流
/*        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        fos.write(101);
        */
        
		#//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是\r\n,linux是\n,mac是\r

字节流写数据如何实现追加写入呢?

使用FileOutputStream的另一个构造方法实现。
public FileOutputStream( String name,boolean append) 创建文件输出流以指定的名称写入文件。如果第二个参数为true,则字节将写入文件的末尾而不是开头。

案例:字节流追加写入

// 35-FileOutputDemo2
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软件打开是有换行的,但是系统本身的记事本打开没有换行;
            // 实际操作之后:
            // idea软件和系统记事本 打开都是有换行的。
        }
        fos.close();
    }
}

字节流写数据加异常处理

finally

特点:被finally控制的语句一定会执行,除非JVM退出。

应用场景介绍
常见应用场景:try…catch…finally,不管程序执行try还是catch,finally都会执行。
// idea_face-finallyPac-FinallyTest
public class FinallyTest {
    public static void main(String[] args) {
        // 常见finally运行情况
        try{
        说明 1System.out.println("11"); 
        说明 2System.out.println(args[0]);
              System.out.println("nomal");
        }catch(Exception e){
             System.out.println("exception");
         }finally{
                System.out.println("finally");
                 }
             }
    }
 说明 1// 输出 说明当执行try选择的时候,会执行finally
// 11
//nomal
//finally
说明 2//输出 说明当执行catch选择的时候,会执行finally
// exception
//finally
情景1:在try、catch中添加return操作,finally块是会被执行的。
// idea_face-finallyPac-FinallyTest2
public class FinallyTest2 {
    public static void main(String[] args) {
        // try、catch加return的情况
        try{
        说明 1System.out.println("11");
        说明 2System.out.println(args[0]);
             System.out.println("nomal");
             return;
        }catch(Exception e){
            System.out.println("exception");
            return;
        }finally{
            System.out.println("finally");
        }
    }
}
说明 1// 输出 说明在try中添加return后,finally块还是会执行。
// 11
//nomal
//finally
说明 2// 输出 说明在catch中添加return后,finally块还是会执行。
// exception
//finally
情景2:在try、catch中添加System.exit()操作,会导致finally块不执行,因为System.exit()会将JVM终止掉。
// idea_face-finallyPac-FinallyTest3
public class FinallyTest3 {
    public static void main(String[] args) {
        // try、catch加System.exit(0)的情况
        try{
        说明 1System.out.println("11");
        说明 2System.out.println(args[0]);
            System.out.println("nomal");
            System.exit(0);
        }catch(Exception e){
            System.out.println("exception");
            System.exit(0);
        }finally{
            System.out.println("finally");
        }
    }
}
说明 1// 输出 表示执行try块中的System.exit()导致finally块不执行
// 11
//nomal
说明 2//输出 表示执行catch块中的System.exit()导致finally块不执行
// exception
具体应用1:在异常处理时提供finally块来执行所有清除操作。比如说IO流中的释放操作

finally和try…catch配合使用:

try{
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}finally{
	执行所有清除操作;
}

案例:

// 35-FileOutputDemo3
public class FileOutputDemo3 {
    public static void main(String[] args){
    
/*        FileOutputStream fos = new FileOutputStream(".\\fos.txt");
        fos.write("hello");
        fos.close();*/
	# 说明 1// 这里报错的原因是 有异常没有被处理。之前都是在main方法声明上通过throws处理IOException
        
   	# 说明 2// 本次通过try..catch处理。
/*        FileOutputStream fos = null;
        try{
            fos = new FileOutputStream(".\\fos.txt");
            fos.write("hello".getBytes());
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        
    # 说明 3// 为了确保在任何情况下 都实现资源释放,即执行 字节流输出流对象.close方法
/*        FileOutputStream fos = null;
        try{
            fos = new FileOutputStream(".\\fos.txt");
            fos.write("hello".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }*/
     # 说明 4// 上述代码中,当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 {
        # 说明 5// 因为fos有问题是空,则这里的就是null。 null调用close会出错 null调用close是空指针异常:NullPointerException,所以需要加 fos为null值的判断。
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        # 说明 6// 上述执行后最终报错: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);
		}
	// 一次读一个字节数组
	int[] bytes = new int[1024];
	int len;
	while((len = fis.read(bytes) != -1){
		System.OutPut.println(new String(bytes,0,len));
	}
3 释放内存空间  对象.close
	fis.close();

字节流读数据方法

方法名说明
int read(int b)从该输入流读取一个字节的数据
返回值是实际读取字节的长度
int read (byte[] b)从该输入流读取最多b.length个字节的数据到一个字节数组
返回值是实际读取字节的长度
案例:字符流读数据(一次读一个字节)
// 35- FileInputStreamDemo
public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        FileInputStream fis = new FileInputStream(".\\fos.txt");

        // 调用字节输入流对象的读数据方法
        # 说明 1int read():从该输入流读取一个字节的数据
 /*       int by = fis.read(); // 读取第一个字符
        System.out.println(by);//这样输出的是数字
        System.out.println((char)by);//这样输出的是字符

        by = fis.read();//读取第二个字符
        System.out.println(by);//这样输出的是数字
        System.out.println((char)by);//这样输出的是字符
*/
		说明 2// 要想读取整个文件内容,可以使用循环,但是循环结束的条件是什么?如果达到文件的尾部,获取的是-1
       /* int by = fis.read();
        while (by != -1) {
            System.out.println((char)by);
            by = fis.read();
        }*/
		
		说明 3//优化上面的程序
        int by;
        while((by = fis.read()) != -1){
            System.out.println((char)by);
        }

        // 释放资源
        fis.close();
    }
}
案例:字节流复制文本文件(一次读写一个字节数据)

需求:把“E:\222\xxx.txt”复制到模块目录下的"xxx.txt"

// 35-InputOutputDemo
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长度数组转换成字符串
// 35-FileInputStreamDemo2
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];

        //第一次读取数据
        int len = fis.read(bys);
        System.out.println(len);
        System.out.println(new String(bys));
        // String(byte[] byte):将字节数组转为String类型

        //第二次读取数据
        len = fis.read(bys);
        System.out.println(len);
        System.out.println(new String(bys));
        // String(byte[] byte):将字节数组转为String类型

        //第三次读取数据
        len = fis.read(bys);
        System.out.println(len);
        // 这个len表示的是读取到的字符的个数
//        System.out.println(new String(bys));
		* 说明:
        // 如果最后一次读取数据没有5个 但是却都转换了 这样不合理
        // String(byte[] bytes,int offset,int length)方法
        System.out.println(new String(bys,0,len));

    /*
    		5
            hello
            5

            wor
            2
            ld
            
            输出结果是上述内容。
            分析:(文件中是这样显示)和视频中讲解一致
            hello\r\n
            world\r\n
            由于字节数组长度是5,每次取五个字节内容:
            第一次读取:hello
            第二次读取:\r\nwor,取的\r\n会在控制台显示换行的空行;
            第三次读取:ld
     		输出结果ld后的换行是System.out.println导致的。
     		因为:read返回的长度是2,说明没有读取后面的\r\n 字符
            */

        // 改进:
        byte[] bys = new byte[1024];//1024及其整数倍
        int len;
        while((len = fis.read(bys)) != -1){
            System.out.println(new String(bys,0,len));
        
        // 释放空间
        fis.close();
    }
}

注意

2022/4/14
字节输入流对象.read(bytes[] bys)
byte[] bys = new byte[1024] 其中的字节数组长度是1024及其倍数
案例:复制图片(一次读写一个字节数组数据)

需求:把“E:\xxx.jpg”复制到模块目录下的“xxx.jpg”

// 35-Demo1
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();
    }
}

字节缓冲流

概述

说明输出字节缓冲流输入字节缓冲流
名字BufferedOutputStreamBufferedInputStream
所在包在java.io包下,使用需要导包的在java.io包下,使用需要导包的
父类OutputStream,说明它是字节输出流InputStream,说明它是字节输入流
解释该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节都进行底层系统的调用,
这句话的意思是:FileOutputStream写字节会调用底层系统;而BufferedOutputStream可以向FileOutputStream这样的输出流写字节
创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

BufferedInputStream和BufferedOutputStream的构造方法

方法名说明
BufferedInputStream(InputStream in)字节缓冲输入流
BufferedOutputStream(OutputStream out)字节缓冲输出流

案例:

// 36-BufferedStreamDemo1
public class BufferedStreamDemo1 {
    public static void main(String[] args) throws IOException {
        //创建字节缓冲输出流
/*        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(".\\bos.txt"));

        // BufferedOutputStream 底层是创建一个长度是8192的字节数组
        //  buf = new byte[size];

        // 写数据
        bos.write("hello\r\n".getBytes());
        bos.write("java\r\n".getBytes());

        // 释放内存
        bos.close();*/


        // 字节缓冲输入流:BufferedInputStream(InputStream in)
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(".\\bos.txt"));

		* 说明:
        // 一次读取一个字节数据
/*        int by;
        while((by = bis.read()) != -1){
            System.out.print((char)by);
        }
        */
        
        * 说明:
        // 一次读取一个字节数组数据
        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();

代码:

// 36-Demo1 
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();

    }

}

xhj小结

文件输入输出流FileInputStream、FileOutputStream参数是 文件的路径字符串 (File对象) 。
输入输出缓冲流BufferedInputStream、BufferedOutputStream参数是 InputStream、OutputStream 也就是可以是FileInputStream、FileOutputStream。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值