java,IO流学习总结

引入

对于计算机来说,所有的数据都是以二进制形式储存。我们可以想象所有的数据都储存在一个“桶”里面。现在想把“桶”里面的水稳定、快速、有指向性的运输到另外一个地方,我们能怎么操作,最好的方法肯定是拿一个水泵,接通管子,以水流的形式进行传输。这样就可以完美满足需求。
计算机也一样,数据的输入/输出操作也是以“流”的形式进行传输的,我们称之为IO流。java.io包下提供提供了各种的关于流的API。我们下面慢慢讲解。
讲解IO流之前,File文件类的了解必不可少。如有不懂可以先了解一下下面这篇博客。点此直接进入
https://blog.csdn.net/qq_45676489/article/details/116243349

流的分类:

●按流的方向划分
输入流、输出流;输入和输出是站在内存的角度出发,或者站在程序的角度,磁盘文件读入程序里面就是输入流,程序里的数据写入磁盘就是输出流。
●按处理数据的类型划分
字节流字符流
字节流:传输的数据是:字节。(0\1表示的二进制数据)。
处理的文件(记事本无法打开)例:图片.jpg、视频.mp4,音频.mp3。
字符流:传输的数据是:字符。(编码表可查到的,能看得懂的)。
处理的文件(记事本可打开)例:文本.txt、C++代码.cpp、java代码.java。
●按功能划分
节点流处理流
节点流:处理数据的基本类型。(处理数据慢)
处理流:对已存在的节点流的封装。(比节点流更快)

分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderwriter
节点流FileInputStreamFileOutputStreamFileReaderFilewriter
缓冲流BufferedFileInputStreamBufferedFileOutputStreamBufferedFileReaderBufferedFilewriter
转换流InputStreamReaderOutputStreamwriter
对象流ObjectInputStreamObjectOutputStream

流的用法

一:输入标准化过程。

  1. 创建Fill类对象,指明读取数据的来源。(此文件在磁盘中要实际存在)
  2. 根据文件类型,创建相应的输入流对象(字节输入流FileInputStream、字符输入流FileReader)。构造器参数为:第一步创建的File类对象。
  3. 具体的读操作。创建对应数组,调用read()方法。字符流创建char数组,字节流创建byte数组。
  4. 调用close方法。实现流对象的关闭。

二:输出标准化过程。

  1. 创建Fill类对象,指明写出数据的位置。(此文件在磁盘中不一定实际存在)
  2. 根据文件类型,创建相应的输入流对象(字节输出流FileOutputStream、字符输入流FileWriter)。构造器参数为:第一步创建的File类对象。
  3. 具体的写操作。调用write()方法。
  4. 调用close方法。实现流对象的关闭。

注:在流操作时会出现异常,请使用try-catch-finaly处理。
下面 一个示例,代表了流的操作的四个步骤,所有流都是如此操作

/*
    实现对文件的复制
     */
    @Test
    public void FileInputOutputStream(){
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            //1、造文件对象
            File srcFile = new File("迪丽热巴.jpg");
            File destFile = new File("迪丽热巴1.jpg");
            //2、造流对象
            fileInputStream = new FileInputStream(srcFile);
            fileOutputStream = new FileOutputStream(destFile);
            //3、读写操作。调用read,write方法
            byte[] buffer = new byte[5];
            int len;
            while ((len = fileInputStream.read(buffer)) != -1){
                fileOutputStream.write(buffer,0,len);
            }
            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        //4、流资源的关闭    
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

部分方法的细节

输入流Fileread

读方法有两种,一个是一次读一个字符,另一个一次读一个字符数组。但两个方法的返回值都为int型,如果读取到文件的末尾,就返回-1.
public int read();
public int read(char[] cbuf);
注:如果使用数组读数据,文件长度不一定刚好是数组长度的整数倍。如果每一次读取的数据都是cbuf.length,就会造成读取数据的异常。我们会定义一个临时变量len,储存读取到数据的长度。这样就不会造成数据错误。

字符输出流FileWriter

构造方法
FileWriter(file,false) / FileWriter(file):对原文件的覆盖,不写第二个参数就默认为对文件的覆盖。
FileWriter(file,true):不会对原文件覆盖,而是在原文件基础上追加内容。
write方法:
public void write(char[] cbuf);
public abstract void write(char[] cbuf, int off, int len);off:开始下标,len:数据长度
注:我们一般不用第一个write方法。因为和上面read方法同样的问题。会造成数据读取错误。write(cubf,0,len)依靠read方法中定义的零时变量len,就可以很好的避开这个问题。

缓冲流

缓冲涉及的类:BufferedInPutStream/BufferedOutPutStream和BufferedWriter/BufferedReader
缓冲流的作用:提供流的读取、写入的速度
速度提升的原因:提供了一个缓冲区。

缓冲流特有的一个方法:readLine();一次读一行。
此方法返回值为String,当读到末尾时,返回null。
readLine和普通read方法对比:

//方式1:char形数组
            //读写操作
//            char[] chars = new char[512];
//            int len;
//            while ((len = bufferedReader.read(chars)) != -1) {
//                bufferedWriter.write(chars, 0, len);
//            }
            //方式2:使用String
            String data;
            while ((data = bufferedReader.readLine()) != null){
                //方法1
//                bufferedWriter.write(data + "\n");//data中不包含换行符
                //方法2
                bufferedWriter.write(data);
                bufferedWriter.newLine();//相当于添加一个换行符

            }

转换流InputStreamReader/OutputStreamWriter

转换流作用: 流对象中可以对读取到的字节数据进行指定编码的编码转换。
InputStreamReader:将一个字节的输入流转换为字符的输入流。相当于解码的过程。看不懂->看得懂
OutputStreamWriter:将一个字符的输出流转换为字节的输出流。相当于编码的过程。看得懂->看不懂
图示:
在这里插入图片描述
转换流的对应构造函数:

InputStreamReader(InputStream);        //通过构造函数初始化,使用的是IDEA默认的编码表utf-8。  
InputStreamWriter(InputStream,String charSet);   //通过该构造函数初始化,可以指定编码表。  
 OutputStreamWriter(OutputStream);      //通过该构造函数初始化,使用的是IDEA默认的编码表utf-8。  
 OutputStreamwriter(OutputStream,String charSet);   //通过该构造函数初始化,可以指定编码表。  

通过转换流改变文件的编码集

 @Test
    public void test2() {
        InputStreamReader isr = null;
        OutputStreamWriter osw = null;
        try {
            File file1 = new File("皇马.txt");
            File file2 = new File("皇马_gdk.txt");

            //字节输入流
            FileInputStream fis = new FileInputStream(file1);
            //字节输出流
            FileOutputStream fos = new FileOutputStream(file2);

            isr = new InputStreamReader(fis,"utf-8");
            osw = new OutputStreamWriter(fos,"gbk");

            //读写过程
            char[] cbuf = new char[20];
            int len;
            while ((len = isr.read(cbuf)) != -1){
                osw.write(cbuf,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (isr != null){
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (osw != null){
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

在这里插入图片描述
此时文件的编码集已被改变,“皇马_gdk.txt”文件IDEA已无法正常打开。

对象流: ObjectInputStream /ObjectOutputStream

ObjectOutputStream:内存中的对象–>存储中的文件、通过网络传输出去:序列化过程
ObjectInputStream:存储中的文件、通过网络接收过来–>内存中的对象:反序列化过程

对象的序列化机制

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的Java对象.
实现序列化的对象所属的类需要满足

  1. 需要实现接口:Serializable
  2. 当前类提供一个全局常量:serialVersionUID
  3. 除了当前Person类需要实现Serializable接口之外,还必须保证其内部所属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值