【JAVA基础】io流详细解读

写在前面

本文根据韩顺平老师的JAVA基础课总结归纳,源码可在个人github找到点击跳转

1.文件

1.1基础知识

区分输入输出流 针对内存

  • 流:数据在数据源(文件)和程序(内存)之间经历的路径
  • 输入流:数据从数据源(文件)到程序(内存)的路径
  • 输出流:数据从程序(内存)到数据源(文件)的路径

img

1.2创建文件

  • new File(String pathname)//根据路径构建一个File对象
  • new File(File parent,String child)//根据父目录文件+子路径构建
  • new File(String parent,String child)//根据父目录+子路径构建
  • createNewFile() 创建新文件

注意:new File只是在java内存中产生文件,真正在磁盘中产生还得使用file.createNewFile()
代码案例

package com.zjh;

import org.junit.jupiter.api.Test;

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

public class FileCreate {
    public static void main(String[] args) {

    }
    //方式1 new File(String pathname)
    @Test
    public void create01() {
        String filePath = "d:\\news1.txt";
        File file = new File(filePath);

        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    //方式2 new File(File parent,String child) //根据父目录文件+子路径构建
    //e:\\news2.txt
    @Test
    public  void create02() {
        File parentFile = new File("d:\\");
        String fileName = "news2.txt";
        //这里的file对象,在java程序中,只是一个对象
        //只有执行了createNewFile 方法,才会真正的,在磁盘创建该文件
        File file = new File(parentFile, fileName);

        try {
            file.createNewFile();
            System.out.println("创建成功~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //方式3 new File(String parent,String child) //根据父目录+子路径构建
    @Test
    public void create03() {
        //String parentPath = "e:\\";
        String parentPath = "d:\\";
        String fileName = "news4.txt";
        File file = new File(parentPath, fileName);

        try {
            file.createNewFile();
            System.out.println("创建成功~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

1.3获取文件信息

基本api

  • getName 文件名
  • getAbsolutePath 绝对路径
  • getParent 父目录
  • length 长度
    • utf-8下 一个英文字符1字节,1个汉字3字节
  • exists 是否存在
  • isFile 是否文件
  • isDirectory 是否目录
package com.zjh;

import org.junit.jupiter.api.Test;

import java.io.File;

public class FileInformation {
    public static void main(String[] args) {

    }
    //获取文件的信息
    @Test
    public void info() {
        //先创建文件对象
        File file = new File("d:\\news1.txt");

        //调用相应的方法,得到对应信息
        System.out.println("文件名字=" + file.getName());
        //getName、getAbsolutePath、getParent、length、exists、isFile、isDirectory
        System.out.println("文件绝对路径=" + file.getAbsolutePath());
        System.out.println("文件父级目录=" + file.getParent());
        System.out.println("文件大小(字节)=" + file.length());
        System.out.println("文件是否存在=" + file.exists());//T
        System.out.println("是不是一个文件=" + file.isFile());//T
        System.out.println("是不是一个目录=" + file.isDirectory());//F


    }
}

1.4目录操作

  • mkdir创建一级目录
  • mkdirs创建多级目录
  • delete删除空目录或文件(delete删除一个目录时,需要确保该目录下面没有文件或者子目录,否则需要先删除文件和字目录)
package com.zjh;

import org.junit.jupiter.api.Test;

import java.io.File;

public class Directory_ {
    //判断 d:\\news1.txt 是否存在,如果存在就删除
    @Test
    public void m1() {

        String filePath = "d:\\news1.txt";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println(filePath + "删除成功");
            } else {
                System.out.println(filePath + "删除失败");
            }
        } else {
            System.out.println("该文件不存在...");
        }

    }

    //判断 D:\\demo02 是否存在,存在就删除,否则提示不存在
    //这里我们需要体会到,在java编程中,目录也被当做文件
    @Test
    public void m2() {

        String filePath = "D:\\demo02";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println(filePath + "删除成功");
            } else {
                System.out.println(filePath + "删除失败");
            }
        } else {
            System.out.println("该目录不存在...");
        }

    }

    //判断 D:\\demo\\a\\b\\c 目录是否存在,如果存在就提示已经存在,否则就创建
    @Test
    public void m3() {
        String directoryPath = "D:\\demo\\a\\b\\c";
        File file = new File(directoryPath);
        if (file.exists()) {
            System.out.println(directoryPath + "存在..");
        } else {
            if (file.mkdirs()) { //创建一级目录使用mkdir() ,创建多级目录使用mkdirs()
                System.out.println(directoryPath + "创建成功..");
            } else {
                System.out.println(directoryPath + "创建失败...");
            }
        }
    }
}
    
public static void main(String[] args) {
        String filePath = "D:\\demo02";
        File file = new File(filePath);
        deleteAll(file);
    }
//递归删除非空目录
    public static void deleteAll(File file){
        if (file.exists()) {
            File files[] = file.listFiles();
            int len = files.length;
            for (int i = 0; i < len; i++) {
                if (files[i].isDirectory()) {
                    deleteAll(files[i]);
                } else {
                    files[i].delete();
                }
            }
            file.delete();
        }
    }

2.IO流原理及分类

2.1IO流原理

img

  • input:读取外部数据到内存(程序)
  • output:将内存(程序)数据输出到外部储存设备中

作用:读写文件、网络通讯

2.2流的分类

  1. 按操作数据单位不同分为:字节流(8 bit)【二进制文件】,字符流(按字符)【文本文件】

注意:处理文本用字符流,而处理图片、视频等二进制文件最好使用字节流,否则可能会造成损失

  1. 按数据流的流向不同分为:输入流,输出流
  2. 按流的角色的不同分为:节点流,处理流(包装/装饰流)

四个基本抽象基类

字节流字符流
输入流InputstreamReader
输出流OnputstreamWriter

派生子类一般都以父类名作为子类后缀
总览:

img

3.文件操作流

3.1FileInputStream和FileOutputStream

  • FileInputStream:文件输入流
  • BufferedInputStream:缓存字节输入流
  • ObjectedInputStream:对象字节输入流

img

3.1.1FileInputStream

主要方法:
创建:

  • FileInputStream(String FilePath)
  • FileInputStream(File file)

读取:

  • public int read()
    • 返回读取的字节
    • 一次读取一个字节,效率低
    • 可以转化为char显示字符
    • 读取中文会乱码(3字节)
  • public int read(byte[] b)
    • 一次读取一个字节数组长度的数据
    • 返回读取的字节数量
    • 读取中文如果是截断读取会乱码,如果刚好都在一个字节数组中读取出来,才不会乱码
package com.zjh;

import org.junit.jupiter.api.Test;

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

public class FileInputStream_ {
    public static void main(String[] args) {
    }

    /**
     * 演示读取文件...
     * 单个字节的读取,效率比较低
     * -> 使用 read(byte[] b)
     */
    @Test
    public void readFile01() {
        String filePath = "C:\\Users\\Mono\\Desktop\\a.txt";
        int readData = 0;
        FileInputStream fileInputStream = null;
        try {
            //创建 FileInputStream 对象,用于读取 文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。
            //如果返回-1 , 表示读取完毕
            while ((readData = fileInputStream.read()) != -1) {
                System.out.print((char)readData);//转成char显示
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源.
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 使用 read(byte[] b) 读取文件,提高效率
     */
    @Test
    public void readFile02() {
        String filePath = "C:\\Users\\Mono\\Desktop\\a.txt";
        //字节数组
        byte[] buf = new byte[8]; //一次读取8个字节.中文截断 byte[30]则完整输出
        int readLen = 0;
        FileInputStream fileInputStream = null;
        try {
            //创建 FileInputStream 对象,用于读取 文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取最多b.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。
            //如果返回-1 , 表示读取完毕
            //如果读取正常, 返回实际读取的字节数
            while ((readLen = fileInputStream.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));//显示
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源.
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

3.1.2FileOutputStream

主要方法:
创建:

  • FileOutputStream(String FilePath , boolean append)
  • FileOutputStream(File file , boolean append)

append为true表示追加模式,为false为覆盖,默认false
写入:当文件不存在,会自动创建(前提是目录存在)

  • write(int b) 写入单字节
  • write(byte [ ] b) 写入字符数组 可以用String.getbytes()将字符串转为字符数组放入
  • write(byte [ ] b,int off ,int len) off起始位置 len长度
package com.zjh;

import org.junit.jupiter.api.Test;

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStream_ {
    public static void main(String[] args) {

    }
    @Test
    public void writeFile() {
        //创建 FileOutputStream对象
        String filePath = "d:\\a.txt";
        FileOutputStream fileOutputStream = null;
        try {
            //得到 FileOutputStream对象 对象
            //老师说明
            //1. new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容
            //2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面
            fileOutputStream = new FileOutputStream(filePath, true);
            //写入一个字节
//            fileOutputStream.write('H');//
            //写入字符串
            String str = "hsp,world!";
            //str.getBytes() 可以把 字符串-> 字节数组
            fileOutputStream.write(str.getBytes());
            /*
            write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流
             */
//            fileOutputStream.write(str.getBytes(), 0, 3);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.1.3文件复制

注意:要使用fileOutputStream.write(buf,0,readLen);,否则对于图片等文件可能会导致写入多余文件而失效

  • 边读取边写入
  • 先关闭输入流再关闭输出流,流判空
package com.zjh;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy {
    public static void main(String[] args) {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        String filePath = "d:\\pic.png";
        String descPath = "d:\\pic2.png";
        try {
            fileInputStream = new FileInputStream(filePath);
            fileOutputStream = new FileOutputStream(descPath);
            byte[] buf = new byte[1024];
            int readLen  = 0;
            while((readLen = fileInputStream.read(buf)) != -1){
                fileOutputStream.write(buf,0,readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(fileInputStream != null){
                    fileInputStream.close();
                }
                if(fileOutputStream != null){
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
}
}

3.2FileReader&FileWriter

字符流可以方便处理字符文件

3.2.1FileReader

创建
FileReader(String/File)
读取

  • public int read()
    • 返回读取的字符
    • 一次读取一个字符,效率低
    • 可以转化为char显示字符
  • public int read(char[] b,int off ,int len)
    • 一次读取一个字符数组长度的数据
    • 返回读取的字符数量
    • 起始off下标 ,len开始
package com.zjh;

import org.junit.jupiter.api.Test;

import java.io.FileReader;
import java.io.IOException;

public class FileReader_ {
    public static void main(String[] args) {

    }
    /**
     * 单个字符读取文件
     */
    @Test
    public void readFile01() {
        String filePath = "d:\\a.txt";
        FileReader fileReader = null;
        int data = 0;
        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取 使用read, 单个字符读取
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 字符数组读取文件
     */
    @Test
    public void readFile02() {
        System.out.println("~~~readFile02 ~~~");
        String filePath = "d:\\a.txt";
        FileReader fileReader = null;

        int readLen = 0;
        char[] buf = new char[8];
        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取 使用read(buf), 返回的是实际读取到的字符数
            //如果返回-1, 说明到文件结束
            while ((readLen = fileReader.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.2.2FileWriter

注意一定要close( ),或者flush( )进行,否则无法写入文件

  • close( )、flush( )的底层都使用了OutPutStream的write( )方法写入
  • close = flush + 关闭
package com.zjh;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriter_ {
    public static void main(String[] args) {
        String filePath = "d:\\note.txt";
        //创建FileWriter对象
        FileWriter fileWriter = null;
        char[] chars = {'a', 'b', 'c'};
        try {
            fileWriter = new FileWriter(filePath);//默认是覆盖写入
//            3) write(int):写入单个字符
            fileWriter.write('H');
            4) write(char[]):写入指定数组
            fileWriter.write(chars);
            5) write(char[],off,len):写入指定数组的指定部分
            fileWriter.write("韩顺平教育".toCharArray(), 0, 3);
//            6) write(string):写入整个字符串
            fileWriter.write(" 你好北京~");
            fileWriter.write("风雨之后,定见彩虹");
            7) write(string,off,len):写入字符串的指定部分
            fileWriter.write("上海天津", 0, 2);
            //在数据量大的情况下,可以使用循环操作.


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //fileWriter.flush();
                //关闭文件流,等价 flush() + 关闭
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("程序结束...");
    }
}

文件不存在会创建文件(前提:目录存在)
String.toCharArray()

4.节点流与处理流

总览

分类字节输入字节输出字符输入字符输出
抽象基类InputStreamOutputStreamReaderWriter
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
访问管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
访问字符串StringReaderStringWriter
以下是处理流
缓存流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
转换流
InputStreamReaderOutputStreamReader
对象流ObjectInputStreamObjectOutputStream
过滤流FilterInputStreamFilterOutputStream
打印流PrintStreamPrintWriter
推回输入流PushbackInputStreamPushbackInputReader
特殊流DataInputStreamDataOutputStream

4.1节点流

节点流:直接与数据源相连,读入或读出。
直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。

4.1.1常用节点流

  • 父 类 :InputStream 、OutputStream、 Reader、 Writer
  • 文 件 :FileInputStream 、 FileOutputStream 、FileReader 、FileWriter 文件进行处理的节点流
  • 数 组 :ByteArrayInputStream、 ByteArrayOutputStream、 CharArrayReader 、CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
  • 字符串 :StringReader、 StringWriter 对字符串进行处理的节点流
  • 管 道 :PipedInputStream 、PipedOutputStream 、PipedReader 、PipedWriter 对管道进行处理的节点流

4.2处理流

处理流和节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。如BufferedReader处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。装饰者模式
注意:使用处理流时只需要关闭处理流,不需要手动关闭节点流,处理流close底层默认会关闭节点流

4.2.1常用处理流

  • 缓冲流:BufferedInputStream 、BufferedOutputStream、 BufferedReader、 BufferedWriter 增加缓冲功能,避免频繁读写硬盘。
  • 转换流:InputStreamReader 、OutputStreamReader实现字节流和字符流之间的转换。
  • 数据流: DataInputStream 、DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来。

5.缓冲流

5.1BufferedReader&BufferedWriter

5.1.1BufferedReader

创建:
BufferedReader (Reader in)
创建使用默认人小的输入缓冲区的缓冲字符输入流。
读取:
public String readLine()
读取到末尾则返回null

package com.zjh;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\a.txt";
        //创建bufferedReader
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        //读取
        String line; //按行读取, 效率高
        //说明
        //1. bufferedReader.readLine() 是按行读取文件
        //2. 当返回null 时,表示文件读取完毕
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
        bufferedReader.close();
    }
}

5.1.2BufferedWriter

创建:
BufferedWriter (Writer out)
写入:

  • write(int b)
  • write(char [ ] b,int off ,int len)
  • write(string b,int off ,int len)
  • newLine();
    • 使用平台自己的系统属性line.separator定义的行分隔符概念。并非所有平台都使用换行符(‘\ n’)来终止行。因此,调用此方法来终止每个输出行,因此优选直接写入换行符
package com.zjh;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\ok.txt";
        //创建BufferedWriter
        //说明:
        //1. new FileWriter(filePath, true) 表示以追加的方式写入
        //2. new FileWriter(filePath) , 表示以覆盖的方式写入
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
        bufferedWriter.write("hello, 韩顺平教育!");
        bufferedWriter.newLine();//插入一个和系统相关的换行
        bufferedWriter.write("hello2, 韩顺平教育!");
        bufferedWriter.newLine();
        bufferedWriter.write("hello3, 韩顺平教育!");
        bufferedWriter.newLine();

        //说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
        bufferedWriter.close();
    }
}

5.1.3文本文件拷贝

package com.zjh.Buffer;

import java.io.*;

public class BufferCopy {
    public static void main(String[] args) {
        String fromPath = "d:\\a.txt";
        String toPath = "d:\\a2.txt";
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            br = new BufferedReader(new FileReader(fromPath));
            bw = new BufferedWriter(new FileWriter(toPath));
            String line;
            while ((line = br.readLine()) != null){
                bw.write(line);
                bw.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(br != null){
                    br.close();
                }
                if(bw != null){
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

5.2BufferedInputStream & BufferedOutputStream

API基本与FileInputStream&FileOutputStream没啥区别,这里省略

5.2.1二进制文件拷贝

可以看到写法基本与上文3.1.3一致,但是效率会更高

package com.zjh.Buffer;

import java.io.*;

public class BufferStreamCopy {
    public static void main(String[] args) {
        String fromPath = "d:\\pic.png";
        String toPath = "d:\\pic2.png";
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(fromPath));
            bos = new BufferedOutputStream(new FileOutputStream(toPath));
            byte[] buf = new byte[1024];
            int readLen  = 0;
            while ((readLen = bis.read(buf)) != -1){
                bos.write(buf,0,readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(bis != null){
                    bis.close();
                }
                if(bos != null){
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

6.对象流

需求:将int num=100数据存放到文件中,读出时可以知道数据内容以及数据类型

  • 序列化就是在保存数据时,保存数据的值和数据类型
  • 反序列化就是在恢复数据时,恢复数据的直和数据类型

需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:

  • Serializable 这是一个标记接口 【推荐】 空接口,无方法
  • Externalizable 用于自定义哪些属性的序列化

6.1ObjectOutStream

使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age),并保存到data.dat 文件中
注意:

  1. 建议在序列化的类中添加serialVersionUID,表示序列化的版本号,可以提高兼容性,即在版本升级时反序列化仍保持对象的唯一性。
    1. 在Dog改变时,系统会认为是修改而不是认为是一个全新的类
  2. 使用Serializable默认序列化所有属性,但是除了static以及transient修饰的属性
    1. 从结果可以看到是null
  3. 序列化对象时,要求里面属性的类型也需要实现序列化接口
    1. 如下面Dog类中的master类对象如果没有实现序列化接口,编译会出错
  4. 序列化具有可继承性,父类序列化,子类默认也序列化
package com.zjh;

import java.io.Serializable;

public class Dog implements Serializable {
    private String name;
    private int age;
    //序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
    private static String nation;
    private transient String color;
    //序列化对象时,要求里面属性的类型也需要实现序列化接口
    //serialVersionUID 序列化的版本号,可以提高兼容性
    private static final long serialVersionUID = 1L;
    //序列化对象时,要求里面属性的类型也需要实现序列化接口
    private Master master = new Master();

    public Dog(String name, int age, String nation, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
        this.nation = nation;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}' + nation ;
    }

    public String getName() {
        return name;
    }

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

package com.zjh.Object;

import com.zjh.Dog;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutStream_ {
    public static void main(String[] args) throws IOException {
        //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
        String filePath = "d:\\data.dat";

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));

        //序列化数据到 d:\data.dat
        oos.writeInt(100);// int -> Integer (实现了 Serializable)
        oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
        oos.writeChar('a');// char -> Character (实现了 Serializable)
        oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
        oos.writeUTF("韩顺平教育");//String
        //保存一个dog对象
        oos.writeObject(new Dog("旺财", 10, "日本", "白色"));
        oos.close();
        System.out.println("数据保存完毕(序列化形式)");
    }
}

6.2ObjectInStream

注意

  1. 读取的顺序要和写入的顺序一致,否则会乱码
package com.zjh.Object;

import com.zjh.Dog;

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

public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //指定反序列化的文件
        String filePath = "d:\\data.dat";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        //读取
        //老师解读
        //1. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致
        //2. 否则会出现异常
        System.out.println(ois.readInt());
        System.out.println(ois.readBoolean());
        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());

        //dog 的编译类型是 Object , dog 的运行类型是 Dog
        Object dog = ois.readObject();
        System.out.println("运行类型=" + dog.getClass());
        System.out.println("dog信息=" + dog);//底层 Object -> Dog

        //这里是特别重要的细节:

        //1. 如果我们希望调用Dog的方法, 需要向下转型
        //2. 需要我们将Dog类的定义,放在到可以引用的位置
        Dog dog2 = (Dog)dog;
        System.out.println(dog2.getName()); //旺财..

        //关闭流, 关闭外层流即可,底层会关闭 FileInputStream 流
        ois.close();
    }
}

7.标准流

System.in 编译InputStream 运行BufferInputStream 键盘输入
System.Out 编译运行PrintStream 显示器
Scanner里面放的就是输入流

Scanner scanner = new Scanner(System.in);
System.out.println("输入内容");
String next = scanner.next();
System.out.println("next=" + next);

8.转换流

  • InputStreamReader:Reader的子类,可以将InputStream字节流(包装)转换为Reader字符流
  • OutputStreamWriter:Writer的子类,可以将OutputStream字节流(包装)转换为Writer字符流

可以指定读取的编码格式和输出的编码格式

需求分析:读取一个编码格式为gbk的文本文件,使用FileInputStream只能按照默认的utf-8格式读取,会导致乱码,这时候就需要指定编码

8.1InputStreamReader

InputStreamReader(Inputstream in,Charset cs) //创建使用给定字符集的
public String getEncoding() 返回此流使用的字符编码的名称。

8.1.1指定读取文件编码

gbk编码文件,使用utf-8读取

img

再使用InputStreamReader(Inputstream in,Charset cs)转换
使用使用BufferedReader提高读取效率

package com.zjh.transformation;

import java.io.*;

public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\a.txt";
        String charset = "gbk";
        //使用FileInputStream读取文件
        //使用InputStreamReader将字节流转为指定编码的字符流
        //使用BufferedReader提高读取效率
        BufferedReader br = new BufferedReader(
                new InputStreamReader(
                new FileInputStream(filePath),charset));
        String s = br.readLine();
        System.out.println(s);
        //关闭最外层即可
        br.close();
    }
}

img

成功

OutputStreamWriter

将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行写入(按照gbk格式,可以指定其他,比如utf-8)
同样使用BufferedWriter提高效率

package com.zjh.transformation;

import java.io.*;

public class OutputStreamWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\hsp.txt";
        String charSet = "gbk";
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), charSet));
        bw.write("hi, 韩顺平教育");
        bw.close();
        System.out.println("按照 " + charSet + " 保存文件成功~");
    }
}

9.打印流

打印流只有输出流没有输入流

9.1PrintStream

img

package com.zjh.print;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

public class PrintStream_ {
    public static void main(String[] args) throws IOException {
        PrintStream out =  System.out;
        out.print("sda手打");
        out.write("张俊鸿".getBytes());
        out.close();
        
        System.setOut(new PrintStream("d:\\hh.txt"));
        PrintStream out2 =  System.out;
        out2.println("的阖家安康和接口大");
        out2.close();
    }
}

System.out是标准输出流 可以用PrintStream out接收
out.print(); 和out.write();的区别:

  • 本质都是字节流的write()方法,print多了一层判空

默认输出位置是控制台
可以使用System.setOut改变输出位置,传入PrintStream(“Path”/File)打印到文本文件中

public void print(String s) {
                if (s == null) {
                    s = "null";
                }
                write(s);
            } 

9.2PrintWriter

img

package com.zjh.print;

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriter_ {
    public static void main(String[] args) throws IOException {
        PrintWriter printWriter = new PrintWriter(new FileWriter("d:\\f2.txt"));
        printWriter.print("hi, 北京你好~~~~");
        printWriter.close();//flush + 关闭流, 才会将数据写入到文件..

    }
}

注意:一定要printWriter.close()或者flush(),否则不会写入,底层close()才真正调用write

10.Properties类

读取配置文件
传统方式

package com.zjh.Properties;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Properties01 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));
        String line = "";
        while ((line = br.readLine())!=null){
            String[] split = line.split("=");
            //如果我们要求指定的ip值
            if("ip".equals(split[0])) {
                System.out.println(split[0] + "值是: " + split[1]);
            }
        }
        br.close();
    }
}

读取遍历,修改也麻烦
使用Properties类方便

10.2Properties

读取key=value格式,不能有空格,值也不需要引号,默认类型是String
方法

  • load:加载配置文件的键值对到Properties对象
  • list:将数据显示到指定设备
  • getProperty(key):根据键获取值
  • setProperty(key,value):设置键值对到Properties对象
  • store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码

10.2读取配置文件

  • getProperty(key):根据键获取值

注意如果是想将读取的String类型转为int或者其他,要用包装类
int age = Integer.parseInt(pro.getProperty("age"));

package com.zjh.Properties;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class Properties02 {
    public static void main(String[] args) throws IOException {
        //使用Properties 类来读取mysql.properties 文件
        //1. 创建Properties 对象
        Properties properties = new Properties();
        //2. 加载指定配置文件
        properties.load(new FileReader("src\\mysql.properties"));
        //3. 把k-v显示控制台
        properties.list(System.out);
        //4. 根据key 获取对应的值
        String user = properties.getProperty("user");
        String pwd = properties.getProperty("pwd");
        System.out.println("用户名=" + user);
        System.out.println("密码是=" + pwd);
    }
}

10.3写入修改

  • properties.setProperty(key,value);
    • 存在就修改value,否则就增加
  • properties.store(OutputStream/Writer,Comment);
    • 使用OutputStream,如果有中文则在配置文件中以unicode编码写出,使用Writer就直接显示中文
    • Comment在配置文件顶部写注释用
package com.zjh.Properties;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class Properties03 {
    public static void main(String[] args) throws IOException {
        //使用Properties 类来创建 配置文件, 修改配置文件内容
        Properties properties = new Properties();

        properties.setProperty("charset", "utf8");
        properties.setProperty("user", "汤姆");//注意保存时,是中文的 unicode码值
        properties.setProperty("pwd", "888888");

        //将k-v 存储文件中即可
//        properties.store(new FileOutputStream("src\\mysql2.properties"), "注释");
        properties.store(new FileWriter("src\\mysql2.properties"), "注释");

        System.out.println("保存配置文件成功~");
    }
}

11.Commons IO

开发中使用封装好的Commons IO类可以简化代码

工具包

网址跳转:链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jiong-952

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

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

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

打赏作者

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

抵扣说明:

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

余额充值