JavaSE复习总结之IO流

x33g5p2x  于2022-03-28 转载在 Java  
字(10.4k)|赞(0)|评价(0)|浏览(362)

IO流概述

输入/输出处理是程序设计中非常重要的环节, 如从键盘或传感器读入数据、 从文件中读取数据或向文件中写入数据、 从网络中读取或写入数据等。 Java 把这些不同类型的输入、 输出抽象为 “流” , 所有的输入/输出以流的形式进行处理。I表示Input,O表示Output,通过IO可以完成硬盘文件的读和写。

IO流的分类

  • 按照流的方向进行分类:
    以内存作为参照物
    往内存中去,叫做输入(Input)。或者叫做读(Read)
    从内存中出来,叫做输出(Output)。或者叫做写(Write)
  • 按照读取数据方式不同进行分类
    有的流是按照字节的方式读取数据,一次读取1个字节byte。这种流称为字节流
    有的流是按照字符的方式读取数据的。这种流称为字符流

在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流

Java中常用的流

文件专属:
	java.io.FileInputStream
	java.io.FileOutputStream
	java.io.FileReader
	java.io.FileWriter
转换流:(将字节流转换成字符流)
	java.io.InputStreamReader
	java.io.OutputStreamWriter
缓冲流专属:
	java.io.BufferedReader
	java.io.BufferedWriter
	java.io.BufferedInputStream
	java.io.BufferedOutputStream
数据流专属:
	java.io.DataInputStream
	java.io.DataOutputStream
标准输出流:
	java.io.PrintWriter
	java.io.PrintStream
对象专属流:
	java.io.ObjectInputStream
	java.io.ObjectOutputStream

InputStream 和 OutputStream 继承结构图:

返回值类型方法名描述
voidclose()关闭此流并释放与该流关联的所有系统资源
abstract intread()从输入流读取下一个数据字节.再读的时候读取不到任何数据返回-1
intread(byte[] b)从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中
intread(byte[] b, int off, int len)将输入流中最多 len 个数据字节读入字节数组
voidflush()刷新此输出流并强制写出所有缓冲的输出字节
voidwrite(byte[] b)将 b.length 个字节从指定的字节数组写入此输出流
voidwrite(byte[] b, int off, int len)将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流
abstract voidwrite(int b)将指定的字节写入此输出流

Reader 和 Writer 继承结构图:

返回值类型方法名描述
abstract voidclose()关闭该流
intread()读取单个字符
intread(char[] cbuf)将字符读入数组
abstract intread(char[] cbuf, int off, int len)将字符读入数组的某一部分
Writerappend(char c)将指定字符追加到此 writer
abstractvoid flush()刷新此流
voidwrite(char[] cbuf)写入字符数组
abstract voidwrite(char[] cbuf, int off, int len)写入字符数组的某一部分
voidwrite(int c)写入单个字符
voidwrite(String str)写入字符串
voidwrite(String str, int off, int len)写入字符串的某一部分
  • 所有的流都实现了java.io.Closeable接口,都是可关闭的,都有close()方法。用完之后一定要关闭,不然会耗费(占用)很多资源。
  • 所有的输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法。养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。

File类

File 类是 java.io 包中唯一代表磁盘文件和目录的类。 File类和四大家族没有关系,所以File类不能完成文件的读和写。

File类的构造方法

  • File(String filename); filename 是文件名字或绝对路径
  • File(String directoryPath,String filename); directoryPath 是文件的绝对路径
  • File(File f,String filename); f 是代表一个目录的文件对象
File dir = new File("D:/java/tt/");//创建目录
File file = new File("D:/java/tt/file.txt");//创建文件
File file = new File(dir,"file1.txt");//在dir目录下创建文件
File file = new File("D:/java/tt/","file2.txt");//在tt目录下创建文件

File类常用方法

返回类型方法名描述
booleanexits( )判断文件是否存在
booleancreateNewFile()以文件形式新建
booleanmkdir()以目录的形式新建
booleanmkdirs()多重目录的形式新建
booleandelete( )删除 File 对象对应的文件或目录
booleanisFile( )判断文件是否是文件
booleanisDirectory( )判断文件是否是目录
booleancanRead( )判断文件是否可读
booleancanWrite( )判断文件是否可写
longlength( )获取文件的长度 (单位时字节)
longlastModified()获取文件最后一次修改时间,返回从1970年到现在的总毫秒数
StringgetName( )获取文件的名字
StringgetPath( )返回 File 对象对应的路径
StringgetAbsolutePath( )获取文件的绝对路径
StringgetParent( )获取文件的父目录
String[]list( )列出指定目录的全部内容,只列出名称
File[ ]listFiles( )返回包含 File 对象所有子文件和子目录的 File 数组

文件流

文件流主要分为

  • 文件字节输入流 java.io.FileInputStream
  • 文件字节输出流 java.io.FileOutputStream
  • 文件字符输入流 java.io.FileReader
  • 文件字符输出流 java.io.FileWriter

FileInputStream

1、文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
2、字节的方式,完成输入的操作,完成读的操作(硬盘 → 内存)

public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("chapter23/src/tempfile3");
            // 准备一个byte数组,一次最多读取4个字节
            byte[] bytes = new byte[4];
            int readCount = 0;
            //is.read(bytes)的返回值是:读取到的字节数量,不是字节本身
            while((readCount = fis.read(bytes)) != -1) {
            	//将字节数组全部转换成字符串
                System.out.print(new String(bytes, 0, readCount));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally { //在finally语句块当中确保流一定关闭
            if (fis != null) {
                try {
                    fis.close();//关闭流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileInputStream类的其它常用方法:

  • int available():返回流当中剩余的没有读到的字节数量
  • long skip(long n):跳过几个字节不读。

FileOutputStream

字节的方式,完成输出的操作,完成写的操作(内存 → 硬盘)

public class FileOutputStreamTest {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            //文件不存在的时候会自动新建!
            // 这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入。
            //fos = new FileOutputStream("D:\\IO\\why\\b.txt");
            // 以追加的方式在文件末尾写入。不会清空原文件内容。
            fos = new FileOutputStream("D:\\IO\\why\\b.txt", true);
            byte[] bytes = {97, 98, 99, 100};
            // 将byte数组全部写出
            fos.write(bytes); // abcd
            // 将byte数组的一部分写出
            fos.write(bytes, 0, 2); // 再写出ab
            String s = "我是输出流";
            // 将字符串转换成byte数组。
            byte[] bs = s.getBytes();
            fos.write(bs);
            fos.flush();// 写完之后,最后一定要刷新
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流(代码省略)
        }
    }
}

FileReader

文件字符输入流,只能读取普通文本。读取文本内容时,比较方便快捷。

public class FileReaderTest {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            //创建文件字符输入流
             reader = new FileReader("D:\\IO\\why\\b.txt");
            //开始读
            char[] chars = new char[4]; // 一次读取4个字符
            int readCount = 0;
            while((readCount = reader.read(chars)) != -1) {
                System.out.print(new String(chars,0,readCount));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流(代码省略)
        }
    }
}

FileWriter

文件字符输出流,负责写。只能输出普通文本

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter out = null;
        try {
            out = new FileWriter("D:\\IO\\why\\c.txt", true);
            char[] chars = {'我','是','中','国','人'};
            out.write(chars); //将我是中国人写入到文件
            out.write(chars, 2, 3);//将中国人写入到文件
            out.write("我是一名java软件工程师!");
            out.write("\n");// 写出一个换行符。
            out.write("hello world!");
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流(代码省略)
        }
    }
}

缓冲流

缓冲流主要是为了提高效率而存在的,减少物理读取次数,缓冲流主要有:

  • 字符输入缓冲流:java.io.BufferedReader
  • 字符输出缓冲流:java.io.BufferedWriter
  • 字节输入缓冲流:java.io.BufferedInputStream
  • 字节输出缓冲流:java.io.BufferedOutputStream

BufferedReader

带有缓冲区的字符输入流。 使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲。

public class BufferedReaderTest {
    public static void main(String[] args) throws Exception{

        FileReader reader = new FileReader("D:\\IO\\why\\a.txt");
        // 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
        // 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流
        // FileReader就是一个节点流BufferedReader就是包装流/处理流。
        BufferedReader br = new BufferedReader(reader);
        // 读一行但不带换行符
        //String firstLine = br.readLine();
        String s = null;
        while((s = br.readLine()) != null){
            System.out.print(s);
        }
        // 对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭
        br.close();
    }
}

BufferedWriter

带有缓冲的字符输出流

public class BufferedWriterTest {
    public static void main(String[] args) throws Exception{
        // 带有缓冲区的字符输出流
        BufferedWriter out = new BufferedWriter(new FileWriter("copy"));
        // 开始写
        out.write("hello world!");
        out.write("\n");
        out.write("hello kitty!");
        // 刷新
        out.flush();
        // 关闭最外层
        out.close();
    }
}

转换流

转换流主要有两个 InputStreamReader 和 OutputStreamWriter

  • InputStreamReader 主要是将字节流输入流转换成字符输入流
  • OutputStreamWriter 主要是将字节流输出流转换成字符输出流
//字节输入流
FileInputStream in = new FileInputStream("Copy02.java");
//通过转换流转换(InputStreamReader将字节流转换成字符流)
InputStreamReader reader = new InputStreamReader(in);
//字节输出流
FileOutputStream out = new FileOutputStream("copy", true);
//通过转换流转换(OutputStreamWriter将字节流转换成字符流)
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(out);

标准输出流

标准输出流主要包含两个:

  • PrintStream
  • PrintWriter

PrintStream

System.out 其实对应的就是 PrintStream,默认输出到控制台,我们可以重定向它的输出,可以定向到文件,也就是执行 System.out.println(“hello”)不输出到屏幕,而输出到文件

public class PrintStreamTest {
    public static void main(String[] args) throws Exception{
		//默认输出到控制台
        System.out.println("hello world!");
        //标准输出流不再指向控制台,指向“log”文件。
        PrintStream printStream = new PrintStream(new FileOutputStream("log"));
        //修改输出方向,将输出方向修改到"log"文件。
        System.setOut(printStream);
        //再输出
        System.out.println("hello world");
        System.out.println("hello kitty");
        System.out.println("hello zhangsan");
	    //标准输出流不需要手动close()关闭
    }
}

PrintWriter

PrintWriter printWriter = new PrintWriter(new FileWriter("D:\\IO\\why\\f.txt"));
printWriter.print("我是printWriter");
printWriter.flush();
printWriter.close();

数据流

数据流包含两个:

  • 数据字节输入流:java.io.DataInputStream
  • 数据字节输出流:java.io.DataOutputStream

DataOutputStream

这个流可以将数据连同数据的类型一并写入文件
注意:这个文件不是普通文本文档

public class DataOutputStreamTest {
    public static void main(String[] args) throws Exception{
        // 创建数据专属的字节输出流
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data"));
        byte b = 100;
        short s = 200;
        int i = 300;
        long l = 400L;
        float f = 3.0F;
        double d = 3.14;
        boolean sex = false;
        char c = 'a';
        // 把数据以及数据的类型一并写入到文件当中
        dos.writeByte(b); 
        dos.writeShort(s);
        dos.writeInt(i);
        dos.writeLong(l);
        dos.writeFloat(f);
        dos.writeDouble(d);
        dos.writeBoolean(sex);
        dos.writeChar(c);
        dos.flush();//刷新
        dos.close();//关闭最外层流
    }
}

DataInputStream

DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提前知道写入的顺序。读的顺序需要和写的顺序一致。才可以正常取出数据

public class DataInputStreamTest01 {
    public static void main(String[] args) throws Exception{
    	//创建数据输入流
        DataInputStream dis = new DataInputStream(new FileInputStream("data"));
        // 开始读,读的顺序需要和写的顺序一致
        byte b = dis.readByte();
        short s = dis.readShort();
        int i = dis.readInt();
        long l = dis.readLong();
        float f = dis.readFloat();
        double d = dis.readDouble();
        boolean sex = dis.readBoolean();
        char c = dis.readChar();
        System.out.println(b);
        System.out.println(s);
        System.out.println(i + 1000);
        System.out.println(l);
        System.out.println(f);
        System.out.println(d);
        System.out.println(sex);
        System.out.println(c);
        dis.close();
    }
}

对象流

对象流可以将 Java 对象转换成二进制写入磁盘,这个过程通常叫做序列化,并且还可以从磁盘读出完整的 Java 对象,而这个过程叫做反序列化。对象流主要包括ObjectInputStream 和 ObjectOutputStream

ObjectOutputStream

  • 参与序列化和反序列化的对象,必须实现Serializable接口
public class Student implements Serializable {
    // IDEA工具自动生成序列化版本号。
    //private static final long serialVersionUID = -7998917368642754840L;
    // 建议将序列化版本号手动的写出来。不建议自动生成
    private static final long serialVersionUID = 1L; // java虚拟机识别一个类的时候先通过类名,如果类名一致,再通过序列化版本号。
    private int no;
    private String name;

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }
   /*setter and getter 方法*/
   /*toString()方法*/
}

序列化对象

public class ObjectOutputStreamTest {
    public static void main(String[] args) throws Exception{
        // 创建java对象
        Student s = new Student(1111, "张三");
        // 创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
        // 序列化对象
        oos.writeObject(s);
        // 刷新
        oos.flush();
        // 关闭
        oos.close();
    }
}

ObjectInputStream

反序列化对象

public class ObjectInputStreamTest {
    public static void main(String[] args) throws Exception{
    	//创建对象输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
        // 开始反序列化,读
        Object obj = ois.readObject();
        // 反序列化回来是一个学生对象,所以会调用学生对象的toString方法。
        System.out.println(obj);
        ois.close();
    }
}

IO+Properties的联合应用

经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,服务器也不需要重启。就可以拿到动态的信息。
类似于以上机制的这种文件被称为配置文件。
并且当配置文件中的内容格式是:
key1=value
key2=value

public class IoPropertiesTest {
    public static void main(String[] args) throws Exception{
        /*
        Properties是一个Map集合,key和value都是String类型。
        想将userinfo文件中的数据加载到Properties对象当中。
         */
        // 新建一个输入流对象
        FileReader reader = new FileReader("chapter23/userinfo.properties");
        // 新建一个Map集合
        Properties pro = new Properties();
        // 调用Properties对象的load方法将文件中的数据加载到Map集合中
        // 文件中的数据顺着管道加载到Map集合中,其中等号=左边做key,右边做value
        pro.load(reader); 
        // 通过key来获取value呢?
        String username = pro.getProperty("username");
        System.out.println(username);
        String password = pro.getProperty("password");
        System.out.println(password);
        String data = pro.getProperty("data");
        System.out.println(data);
        String usernamex = pro.getProperty("usernamex");
        System.out.println(usernamex);
    }
}

相关文章