Java之I/O流--适合新手小白一篇通解

在学习I/O流之前我们需要大致了解一下字符集编码的详细情况

字符集编码

注:字符编码和解码要使用相同的字符集,否则会出现乱码
英文数字一般不会出现乱码,许多字符集都兼容了ascll编码
在Java中我们默认使用的是UTF-8编码

Java中的I/O流通常包括两大类——字节流和字符流

字节流和字符流对比

1.字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。用一句话说就是:字节流可以处理一切文件,而字符流只能处理纯文本文件

2.字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。而字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了

字节流的各类流之间的关系

了解各类流之间的关系很有必要在这里插入图片描述

作为初学者的我们可能都会有这样一个疑问:
什么是输入流,什么是输出流,而且有什么区别,分别是什么时候使用?
A:我们首先要明白:输入输出是相对于程序本身而言
B: 比如:输入流相对于程序本身而言就是从文件中输入到程序里面------换句话说就是读文件
想当然那么输出流就是从文件中输出到文件中-----写文件

字节流各种子类对比—这里以字节输入流为例

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

字符流的各类流之间的关系----以输入流为例

两大父类:Writer Reader

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

WriterReader结构类似,方向相反,不再赘述。唯一有区别的是,Writer的子类PrintWriter

缓冲流和缓冲池

字节流的缓冲区

逐个字节对文件进行读写效率很低(文件在硬盘中,我们的程序在内存中,而计算机对内存的操作是很快的,所以我们可以通过手动设置一个字节缓冲区对文件进行读写的操作)

package IO.File.Stream;

import java.io.FileInputStream;
import java.io.IOException;

public class FileInput2 {
    public static void main(String[] args) throws IOException {
        FileInputStream file2=new FileInputStream("data/java.txt");
        byte []bytes=new byte[1024];//设置一个1kb大小的字节形式的数组作为缓冲区
        int len;
        while((len= file2.read(bytes))!=-1){//将读到的字节数储存在bytes数组中,并返回读取的字节数,返回值不为-1说明还有字节没读完
            System.out.print(new String(bytes,0,len));//将指定长度的字节数组转化为字符串
        }
        file2.close();
    }
}

字节缓冲流

在Java中有缓冲流内置了缓冲池,可以大大的提高读写效率
同时可以通过构造方法,扩大缓冲池的大小
但是需要注意:缓冲池的大小不是越大越好,在一定程度内可以提高提高读写效率
达到一定程度后,效率的提升就不是很明显了,反而会导致内存占用过多,得不偿失

package IO.File.Stream;

public class Demo_BufferedStream{
        public static void main(String[] args) throws IOException{

        //1.创建字节缓冲,输入输出流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\a.flv"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileInputStream("D:\\b.flv"));

        //2.读写操作
        int i;
        while((i=bis.read())!=-1){
            bos.write(i);
        }

        //3.关闭流释放资源
        bis.close();
        bos.close();

    }
}


补充1:文件操作+案例(File类的常用方法需要掌握)

package IO.File;

import java.io.File;
import java.io.IOException;

public class file_abilities {
    public static void main(String[] args) throws IOException {
        File f1 = new File("D:\\微信文件保存\\wx.txt");
        //在指定目录下创建文件(文件不存在就创建文件并返回true,存在就返回false  )
        System.out.println(f1.createNewFile());
//        delete()方法用于删除文件/目录(相对路径和绝对路径)
        File f2=new File("D:\\微信文件保存\\JavaSE");//创建单级目录
        System.out.println(f1.mkdir());
        File f3=new File("D:\\微信文件保存\\JavaWeb\\HTML");
        System.out.println(f3.mkdirs());//创建多级目录
    }
}

文件查询案例 -----结合此案例可以更好的理解并熟悉File类相应的方法与操作

package IO.File.Stream;

import java.io.File;
import java.io.IOException;

public class SearchFile {
    public static void main(String[] args) throws IOException {
    //需要在哪个文件夹中查询
        File f1 = new File("D:/");
        search(f1, "Whale.exe");
    }

    public static void search(File f1, String name) throws IOException {
        if (f1.isFile() || !f1.exists() || f1 == null) {
            System.out.println("无法搜索!!!");
            return;
        }
        File[] files = f1.listFiles();//
        //文件夹不为空且里面有文件
        if (files != null && files.length > 0) {
            for (File e : files) {
                if (e.isFile()) {
                //关键操作
                    if (e.getName().contains(name)) {
                        System.out.println("搜索成功,文件路径为:" + e.getAbsolutePath());
                        //如果需要查询并打开,可以添加如下语句,执行相应的程序
//                        Runtime run=Runtime.getRuntime();
//                        run.exec(e.getAbsolutePath());
                    }
                } 
                //递归操作
                else {
                    search(e, name);
                }
            }
        }
    }
}

补充2:输出语句的重定向

System.out.println();相信大家都很熟悉了,那out是什么呢?
out其实是一个输出流对象,默认时out的值null,故默认我们输出到的时控制台
但我们可以通过System类的setout方法对输出语句重定向更新为新的输出流对象,从而达到相应的开发目的
下面的案例就是一个很好的体现:

package IO.File.Stream;

import java.io.IOException;
import java.io.PrintStream;
//输出语句的重定向
public class printstream {
    public static void main(String[] args) {
        System.out.println("老骥伏枥");//默认out为null->console
        try (PrintStream printStream = new PrintStream("data/TX.txt")) {
            System.setOut(printStream);//重新设置out对象
            System.out.println("志在千里");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

补充3:数据输出流的实际使用案例

在这里推荐大家在I/O流中的异常处理中使用try-with-resource语句,而不是直接抛出异常
这样可以避免忘记释放资源导致文件读写失败,同时又处理了异常
为以后的开发保持一个良好的习惯

package IO.File.Stream;

import java.io.*;

public class otherbytestream {
    public static void main(String[] args) {
        File file = new File("java.txt");
//   DataInputStream本身还是一种字节输入流(数据流),但相较于fileinputstream他拥有可以自动解析编码的方法(方便写基本数据类型的数据)
        try(DataOutputStream dataOutputStream=new DataOutputStream(new FileOutputStream(file))){
            dataOutputStream.writeInt(111);
        }catch (IOException e){
            e.printStackTrace();
        }
        try(DataInputStream dataInputStream=new DataInputStream(new FileInputStream(file))){
            System.out.println(dataInputStream.readInt());
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

补充4:对象输出流实际使用案例分析

对对象的读写操作,要求该对象是可序列化的/反序列化
在Java中提供了相应的接口可以为对象实现序列化操作
如果对象中的某个成员不想序列化可以通过transient修饰来解决

package IO.object;

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private String password;
    private int num;
    private char gender;

    public User() {
    }
    public User(int num, char gender, String name, String password) {
        this.num=num;
        this.gender=gender;
        this.name=name;
        this.password=password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return num+","+gender+","+name+","+password;
    }
}
package IO.object;

import java.io.*;
//对象的读取操作
public class objecttest1 {
    public static void main(String[] args) {
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("data/object.txt"))) {
            User user=new User(1,'男',"YK0307","1243566");
            objectOutputStream.writeObject(user);
        }catch (IOException e){
            e.printStackTrace();
        }
        try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("data/object.txt"))) {
        //返回是是Object类型的,需要强制转化为User类型的
            User user1=(User) objectInputStream.readObject();
            System.out.println(user1);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
  • 22
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

永恒的码农

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值