6 io流

1 初识io流

IO,即in和out,也就是输入和输出,指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。

Java 中是通过流处理IO 的,那么什么是流?

流(Stream),是一个抽象的概念,是指一连串的数据(字符或字节),是以先进先出的方式发送信息的通道。

当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。

一般来说关于流的特性有下面几点:

  1. 先进先出:最先写入输出流的数据最先被输入流读取到。
  2. 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile除外)
  3. 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。
    3.2 IO流分类
    IO流主要的分类方式有以下3种:
    按数据流的方向:输入流、输出流
    按功能:字符流,字节流
    按名字:字符输入流,字符输出流,字节输入流,字节输出流。
1.1 输入流与输出流

输入与输出是相对于应用程序而言的,比如文件读写,读取文件是输入流,写文件是输出流,这点很容易搞反。
在这里插入图片描述

1.2 字节流与字符流

字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同,字节流操作的单元是数据单元是8位的字节,字符流操作的是数据单元为16位的字符。
为什么要有字符流?Java中字符是采用Unicode标准,Unicode 编码中,一个英文字母或一个中文汉字为两个字节。

而在UTF-8编码中,一个中文字符是3个字节。例如下面图中,“云深不知处”5个中文对应的是15个字节:-28-70-111-26-73-79-28-72-115-25-97-91-27-92-124

在这里插入图片描述

那么问题来了,如果使用字节流处理中文,如果一次读写一个字符对应的字节数就不会有问题,一旦将一个字符对应的字节分裂开来,就会出现乱码了。为了更方便地处理中文这些字符,Java就推出了字符流。

字节流和字符流的其他区别:

字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。用一句话说就是:字节流可以处理一切文件,而字符流只能处理纯文本文件。
字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。而字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了。
1.3 File类

File类是用来操作文件的类,但它不能操作文件中的数据。
File类实现了Serializable、 Comparable,它是支持序列化和排序的。
File类的构造方法
在这里插入图片描述

File类的常用方法
在这里插入图片描述

代码1:

public class FileTest {
    public static void main(String[] args) {
        File file = new File("D:\\iotest");
        boolean state=file.exists();
        System.out.println(state);

        File file1 = new File("D:\\iotest\\file\\test01");
        boolean state1=file1.exists();
        if(!state1){
            file1.mkdirs();//创建多级文件夹
        }

        File file2 = new File("D:\\iotest\\file\\test01\\a.txt");
        if(!file2.exists()){
            try {
                file2.createNewFile();//创建一个文件
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        File file3=new File("D:\\qy141");
        File[] lists=file3.listFiles();//子文件
        for(File f1:lists){
            System.out.println(f1.getAbsolutePath());
        }
    }

查找文件:

public class FileTools {
    public static void main(String[] args) {
        File file3=new File("D:\\qy141");
        bianli(file3);
    }
    public static void bianli(File file){
        File[] lists=file.listFiles();//子文件
        for(File f1:lists){
            System.out.println(f1.getAbsolutePath());
            if(f1.isDirectory()){
                bianli(f1);//递归:自己调用自己
            }
        }
        
    }
}
1.4 字节流
InputStream与OutputStream是两个抽象类,是字节流的基类,所有具体的字节流实现类都是分别继承了这两个类。 

InputStream的关系继承图

InputStream:InputStream是所有字节输入流的抽象基类,前面说过抽象类不能被实例化,实际上是作为模板而存在的,为所有实现类定义了处理输入流的方法。
FileInputSream:文件输入流,一个非常重要的字节输入流,用于对文件进行读取操作。
PipedInputStream:管道字节输入流,能实现多线程间的管道通信。
ByteArrayInputStream:字节数组输入流,从字节数组(byte[])中进行以字节为单位的读取,也就是将资源文件都以字节的形式存入到该类中的字节数组中去。
FilterInputStream:装饰者类,具体的装饰者继承该类,这些类都是处理类,作用是对节点类进行封装,实现一些特殊功能。
DataInputStream:数据输入流,它是用来装饰其它输入流,作用是“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”。
BufferedInputStream:缓冲流,对节点流进行装饰,内部会有一个缓存区,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送,效率更高。
ObjectInputStream:对象输入流,用来提供对基本数据或对象的持久存储。通俗点说,也就是能直接传输对象,通常应用在反序列化中。它也是一种处理流,构造器的入参是一个InputStream的实例对象。
OutputStream类继承关系图:
在这里插入图片描述

字节流方法

字节输入流InputStream主要方法:
public static void main(String[] args) {
    /*File file3=new File("D:\\qy141");
    bianli(file3);*/
    File f1=new File("D:\\java01\\Class07.java");//文本文件
    read(f1);
}

//读得必须是一个文件
public static void read(File file){
    //流——输入——字节输入流——基础流
    try {
        InputStream is=new FileInputStream(file);
        //读
        int a;
        int[] ints=new int[1024];
        int i=0;
        for(;(a=is.read())!=-1;i++){
            ints[i]=a;//d读取得内容放到数组
        }
        System.out.println(new String(ints,0,i));
        //只将读取得转换,空得数组不转换
        is.close();
        /*1.读出来得东西看不懂   什么时候到头不知道 效率低
        int a=is.read();//01010101
        System.out.println(a);
        a=is.read();//01010101
        System.out.println(a);*/
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
循环读取:
public static void main(String[] args) {
    /*File file3=new File("D:\\qy141");
    bianli(file3);*/
    File f1=new File("D:\\qy141\\java01\\src\\java01\\Class07.java");//文本文件
    read(f1);
}
public static void read2(File file){
    try {
        InputStream is = new FileInputStream(file);
        byte[] bytes=new byte[100];
        int length;
        while((length=is.read(bytes))!=-1){
            System.out.println(new String(bytes,0,length));
            //避免空的  避免重复得转换
        }
    }catch (Exception e){
        e.printStackTrace();
    }
}

字节输出流OutputStream主要方法:

public static void write1(){
    File file = new File("D:\\iotest\\a.txt");
    if(!file.exists()){
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        //字节流   输出流    基础流
        OutputStream os=new FileOutputStream(file,true);//默认:覆盖书写  append:true
        //写东西
        //os.write(120);8个01对应的数字——一个字节
        String str="Hello World!";
        byte[] bytes=str.getBytes();
        os.write(bytes);
        os.flush();//强制将缓存中的东西推送到琉——刷新缓存
        os.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }


}
字节包装流——缓冲流 
	构造1BufferedInputStream(InputStream in)
	构造2BufferedInputStream(InputStream in,int size)
	      第一种形式的构造方法创建带有32个字节缓冲区的缓冲流
	 第二种形式的构造方法按指定的大小来创建缓冲区
	BufferedOutputStream()
	构造1BufferedOutputStream(OutputStream in)
	构造2BufferedOutputStream(OutputStream in,int size)
public static void read3(){
    File f1=new File("D:\\qy141\\java01\\src\\java01\\Class07.java");//文本文件
    try {
        InputStream is = new FileInputStream(f1);
        BufferedInputStream bis=new BufferedInputStream(is);//参数:基础流——提供了额外的功能——缓存区
        byte[] bytes=new byte[100];//缓存数组
        int length;
        while((length=bis.read(bytes))!=-1){//length=is.read(bytes)读取然后返回得读取得长度
            System.out.println(new String(bytes,0,length));//避免空得  避免得重复得转换
        }
        bis.close();
    }catch (Exception e){
        e.printStackTrace();
    }
}

public static void write2(){
    try {
        //字节流   输出流    基础流
        OutputStream os=new FileOutputStream("D:\\iotest\\b.txt",true);//默认:覆盖书写  append:true
        BufferedOutputStream bos=new BufferedOutputStream(os);
        //写东西
        String str="Hello World!";
        byte[] bytes=str.getBytes();
        bos.write(bytes);
        bos.flush();//强制将缓存中的东西推送到琉——刷新缓存
        bos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

文件拷贝:
// 对文件做读写——文本文件——其他没有办法直接都城文本或者写文本
// 拷贝——文件转换成输入流——写道输出流中——所以:什么文件都行
//61090

public static void copy1(File oldfile){
    File fileNew=new File("D://12号New.zip");
    //将原文件转成输入流
    try {
        long l1=System.currentTimeMillis();
        InputStream  is=new FileInputStream(oldfile);
        //将目的文件转成输出流
        OutputStream os=new FileOutputStream(fileNew);
        //将输入流读取——写道输出流
        int length;
        byte[] bytes=new byte[1024];
        while((length=is.read(bytes))!=-1){
            os.write(bytes,0,length);
        }
        os.flush();
        os.close();
        is.close();
        long l2=System.currentTimeMillis();
        System.out.println(l2-l1);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//17002
public static void copy2(File oldfile){
    File fileNew=new File("D://12号New.zip");
    //将原文件转成输入流
    try {
        long l1=System.currentTimeMillis();
        InputStream  is=new FileInputStream(oldfile);
        BufferedInputStream bis=new BufferedInputStream(is);
        //将目的文件转成输出流
        OutputStream os=new FileOutputStream(fileNew);
        BufferedOutputStream bos=new BufferedOutputStream(os);
        //将输入流读取——写道输出流
        int length;
        byte[] bytes=new byte[1024];
        while((length=bis.read(bytes))!=-1){
            bos.write(bytes,0,length);
        }
        bos.flush();
        bos.close();
        bis.close();
        long l2=System.currentTimeMillis();
        System.out.println(l2-l1);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
字节包装流:——对象流(序列化)

功能:new Student(“zs”,11)——这个对象存储起来——文件中
对象:new Array Map Studentnew的一个个对象——原本堆区——内存
存储放到其他的地方:
文件中——:首先将对象序列化:对象以特殊形式进行转换,获取一个字符串的东西——序列化——写到文件(对象流:对象进行序列化写道文件)
序列化:对象-》字节
做缓存。

	public static void duixiang(){
    //将对象写道文件里
    try {
        OutputStream os=new FileOutputStream("D://iotest//aaa.obj");
        ObjectOutputStream oos=new ObjectOutputStream(os);
        Student stu=new Student("zs",11);//序列化,必须实现Serializable 接口
        oos.writeObject(stu);
        oos.flush();
        oos.close();

        InputStream is=new FileInputStream("D://iotest//aaa.obj");
        ObjectInputStream  ois=new ObjectInputStream(is);
        Student stu1= (Student) ois.readObject();//文件中
        System.out.println(stu1.getAge()+"---"+stu1.getName());
        System.out.println(stu1);
        System.out.println(stu);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}
1.5 字符流

与字节流类似,字符流也有两个抽象基类,分别是Reader和Writer。其他的字符流实现类都是继承了这两个类。
以Reader为例,它的主要实现子类如下图:

InputStreamReader:从字节流到字符流的桥梁(InputStreamReader构造器入参是FileInputStream的实例对象),它读取字节并使用指定的字符集将其解码为字符。它使用的字符集可以通过名称指定,也可以显式给定,或者可以接受平台的默认字符集。
BufferedReader:从字符输入流中读取文本,设置一个缓冲区来提高效率。BufferedReader是对InputStreamReader的封装,前者构造器的入参就是后者的一个实例对象。
FileReader:用于读取字符文件的便利类,new FileReader(File file)等同于new InputStreamReader(new FileInputStream(file, true),"UTF-8"),但FileReader不能指定字符编码和默认字节缓冲区大小。
PipedReader :管道字符输入流。实现多线程间的管道通信。
CharArrayReader:从Char数组中读取数据的介质流。
StringReader :从String中读取数据的介质流。

Writer与Reader结构类似,方向相反,不再赘述。唯一有区别的是,Writer的子类PrintWriter。
字符流方法
字符输入流Reader主要方法:

public static void copy3(File oldFile){
    File newFile=new File("D:\\iotest\\aa.txt");

    try {
        Reader reader=new FileReader(oldFile);
        Writer writer=new FileWriter(newFile);

        char[] chars=new char[1024];
        int length;
        while((length=reader.read(chars))!=-1){
            writer.write(chars,0,length);
        }
        writer.write("已经拷贝完毕");
        writer.flush();
        writer.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

字符输出流Writer主要方法:
另外,字符缓冲流还有两个独特的方法。
BufferedWriter类newLine() :写入一个行分隔符。这个方法会自动适配所在系统的行分隔符。
BufferedReader类readLine() :读取一个文本行。

public static void main(String[] args) {
    copy4(new File("D:\\iotest\\a.txt"));
    //duixiang();
}
public static void copy4(File oldFile){
    File newFile=new File("D:\\iotest\\aa.txt");
    try {
        Reader reader=new FileReader(oldFile);
        BufferedReader bread=new BufferedReader(reader);
        Writer writer=new FileWriter(newFile);
        BufferedWriter bwriter=new BufferedWriter(writer);
        char[] chars=new char[1024];
        int length;
        while((length=bread.read(chars))!=-1){
            bwriter.write(chars,0,length);
        }
        bwriter.newLine();
        bwriter.write("已经拷贝完毕");
        bwriter.flush();
        bwriter.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}
1.6 转换流:

在这里插入图片描述

InputStreamReader和OutputStreamWriter是字节流和字符流之间的转换类
InputStreamReader(InputStream in):类是从字节流到字符流的桥接器:它使用指定的字符集读取字节并将它们解码为字符

FileReader:将读取 的字节转换成字符,默认的——发生乱码
OutputStreamWriter(outPutStream os);是字符通向字节流的桥梁:可以指定的charset将要写入流中的字符编码成字节。(编码:能看懂的字符变为看不懂的字节)

InputStreamReader(InputStream in,“gb2312”); //将读取的字节流抓换成字符流	_可以指明编码格式
OutputStreamWriter(outPutStream os”utf-8”); //将书写的字符转换成字节流——可以指明编码格式
	public static void main(String[] args) {
    //源文件:GBK  java环境:utf-8,新建的文件Utf-8
    // 读--字节---java环境:utf-8转换成字符
    // 写——字符---java的utf-8,转换成字节,然后写的文件
    copy5(new File("D:\\iotest\\WebSocketTest.java"));
    //duixiang();
}

public static void copy5(File oldFile){
    File newFile=new File("D:\\iotest\\WebSocketTestNew.java");
    try {
        InputStream is=new FileInputStream(oldFile);// 字节
        InputStreamReader reader=new InputStreamReader(is,"gbk");//按照GBK将字节转换成字符

        OutputStream os=new FileOutputStream(newFile);
        // 写的时候  字符   底层  转成字节
        OutputStreamWriter writer=new OutputStreamWriter(os,"utf-8");//写的字符按照utf-8取字节


        char[] chars=new char[1024];
        int length;
        while((length=reader.read(chars))!=-1){
            writer.write(chars,0,length);
        }
        writer.write("已经拷贝完毕");
        writer.flush();
        writer.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杵意

谢谢金主打赏呀!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值