IO流基础

1、基本概念

1.1、IO模型设计

Java的IO模型设计非常优秀,它使用Decorator(装饰者)模式,按功能划分Stream,可以动态装配这些Stream,以便获得需要的功能。

1. 例如,需要一个具有缓冲的文件输入流,则应当组合使用FileInputStream和BufferedInputStream。

1.2、IO流的分类

1. 按数据流的方向分为:输入流、输出流(此输入、输出是相对于我们写的代码程序而言)
		输入流:从别的地方(本地文件,网络上的资源等)获取资源 输入到 我们的程序(内存)中。
		输出流:从我们的程序中 输出到 别的地方(本地文件), 将一个字符串保存到本地文件中,就需要使用输出流。
2. 按处理数据单位不同分为:字节流、字符流  
        1字符 = 2字节 、 1字节(byte) = 8位(bit),一个汉字占两个字节长度。
        字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码。
        字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。
3. 按功能不同分为:节点流、处理流
		节点流:以从或向一个特定的地方(节点)读写数据。如FileInputStream 
		处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。
		如BufferedReader,处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装。

1.3、基本流

  • 4个基本的抽象流类型,所有的流都继承这四个抽象类。
  • 字节流是一个字节一个字节进行操作,适用于操作二进制文件(视频、音频)
  • 字符流是操作字符,适用于操作文本
  • 按流的角色的不同分为:节点流、处理流/包装流
输入流输出流
字节流InputStreamoutputStream
字符流ReaderWriter

1.4、文件和流的关系图

Java程序\n(内存) 文件(磁盘) 输出流 输入流 Java程序\n(内存) 文件(磁盘)

2、File类

  • File对象只是存在于内存的对象,并不是一个存在于磁盘的文件

2.1、构造方法

// 1、根据路径构建一个File对象
new File(String pathname);

// 2、根据父目录文件 + 子路径构建一个File对象
new File(File parent,String child)
   
// 3、根据父目录 + 子路径构建一个File对象
new File(String parent,String child)

2.2、常用方法

2.2.1、创建新文件
// 创建新文件
public boolean createNewFile();
2.2.2、获取文件的信息
// 获取文件名称 
public String getName();

// 获取文件绝对路径
public String getAbsolutePath();

// 获取文件父级目录
public String getParent();

// 获取文件大小(按文件中字节统计,UTF-8编码1个汉子3个字节,1个英文字符1个字节)
public long length();

// 判断文件是否存在
public boolean exists();

// 判断是不是一个文件
public boolean isFile();

// 判断是不是一个目录
public boolean isDirectory();
2.2.3、目录操作和文件删除
// 创建一级目录(使用该方法创建多级目录返回false)
public boolean mkdir();

// 创建多级目录
public boolean mkdirs();

// 删除空目录或者文件(如何目录下有文件不能删除,只能删除空目录)
public boolean delete();

3、节点流

3.1、InputStream字节输入流

3.1.1、常用类
  • FileInputStream:文件字节节点流
  • BufferedInputStream:缓冲字节处理流
  • ObjectInputStream:对象字节处理流
3.1.2、FileInputStream
3.1.2.1、每次读取一个字节
public static void main(String[] args) throws IOException {
    int charData = 0;
    FileInputStream fileInputStream = null;
    try {
        // 创建FileInputStream对象,用于读取文件
        fileInputStream = new FileInputStream("e:\\hello.txt");
        // 从该输入流读取一个字节的数据,如果没有输入可用,该方法将阻止。返回-1,表示文件读取完毕
        while ((charData = fileInputStream.read()) != -1) {
            // 读取UTF-8编码下的汉字会乱码
            System.out.print((char) charData);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        fileInputStream.close();
    }
}
3.1.2.2、读取数据到字节数组
  • 从该输入流读取最多b.length字节的数据到字节数组,从而减少读取次数。
public static void main(String[] args) throws IOException {
    int charData = 0;
    // 缓冲字节数组
    byte[] buffer = new byte[4];
    FileInputStream fileInputStream = null;
    try {
        // 创建FileInputStream对象,用于读取文件
        fileInputStream = new FileInputStream("e:\\hello.txt");
        // charData返回的是实际读取的字节数
        while ((charData = fileInputStream.read(buffer)) != -1) {
            System.out.print(new String(buffer));
            System.out.println();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        fileInputStream.close();
    }
}

3.2、OutputStream字节输出流

3.2.1、 常用类
  • FileOutputStream:文件字节输出流
3.2.2、FileOutputStream
3.2.2.1、写入一个字节
public static void fileOut() throws IOException {
    FileOutputStream fileOutputStream = null;
    try {
        // 如果没有对应文件会自动创建,但必须要有对应的目录。如果没有对应目录则抛出异常
        fileOutputStream = new FileOutputStream("e:\\test\\test.txt");
        // 写入一个字节
        fileOutputStream.write('h');
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        fileOutputStream.close();
    }
}
3.2.2.2、写入字节数组
  • 当图片、视频、音频等文件一边读到内存一边写到磁盘时,一定要使用write(byte b[], int off, int len)方法
    去写入磁盘,因为最后一次并不能保证byte数组能被读满,如果未读满而全部写入磁盘会导致文件损坏。

    public static void fileOut() throws IOException {
        FileOutputStream fileOutputStream = null;
        String str = "hello,石头人";
        try {
            // 构造参数append为true时,写入文件的数据会追加到原有文件末尾,而不再是覆盖重写。
            fileOutputStream = new FileOutputStream("e:\\test.txt",true);
            // 将字节数组一次性写入文件
            fileOutputStream.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fileOutputStream.close();
        }
    }
    

3.3、Reader字符输入流

3.3.1、常用类
  • FileReader:文件字符输入流
  • BufferedReader:字符缓冲流
3.3.2、FileReader文件字符输入流
3.3.2.1、每次读取一个字符
public static void fileReader() throws IOException {
    int charData = 0;
    FileReader fileReader = null;
    try {
        fileReader = new FileReader("e:\\test.txt");
        // charData是读取到的字符
        while ((charData = fileReader.read()) != -1) {
            System.out.print((char) charData);
        }
    } catch (IOException e) {
		e.printStackTrace();
    } finally {
        if (fileReader != null) {
            fileReader.close();
        }
    }
}
3.3.2.2、读取数据到字符数组
public static void fileReader() throws IOException {
    int charData = 0;
    char[] chars = new char[8];
    FileReader fileReader = null;
    try {
        fileReader = new FileReader("e:\\test.txt");
        // charData是实际读取到的字符数,-1表示读取结束
        while ((charData = fileReader.read(chars)) != -1) {
            // 取实际读取的字符数组内容
            System.out.print(new String(chars, 0, charData));
        }
    } catch (IOException e) {

    } finally {
        if (fileReader != null) {
            fileReader.close();
        }
    }
}
3.3.3、BufferedReader字符缓冲流
  • 常用于包装字符节点流,如(FileReader)

3.4、Writer字符输出流

3.4.1、常用类
  • FileWriter:文件字符输出流
3.4.2、FileWriter
  • FileWriter使用后,必须要关闭(close)或者刷新(flush),否则写入不到指定的文件
3.4.2.1、写单个字符
public static void fileWriter() throws IOException {
    FileWriter fileWriter = null;
    try {
        // append默认是覆盖旧文件内容
        fileWriter = new FileWriter("e:\\test.txt");
        fileWriter.write('h');
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fileWriter != null) {
            fileWriter.close();
        }
    }
}
3.4.2.2、写入数组
public static void fileWriter() throws IOException {
    String str = "hello,石头人";
    char[] chars = str.toCharArray();
    FileWriter fileWriter = null;
    try {
        // append为true时,追加在旧文件末尾
        fileWriter = new FileWriter("e:\\test.txt",true);
        fileWriter.write(chars, 0, chars.length);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fileWriter != null) {
            fileWriter.close();
        }
    }
}
3.4.2.3、写入字符串
public static void fileWriter() throws IOException {
    String str = "hello,石头人";
    FileWriter fileWriter = null;
    try {
        fileWriter = new FileWriter("e:\\test.txt");
        fileWriter.write(str, 0, str.length());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fileWriter != null) {
            fileWriter.close();
        }
    }
}

4. 处理流

4.1、基本介绍

  • 节点流可以从一个特定的数据源读写数据。如:FileReader、FileWriter
  • 处理流(包装流)是”连接“在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能。如:BufferedReader、BufferedWriter

4.2、区别

  • 节点流是底层流/低级流,直接跟数据源相连
  • 处理流/包装流是包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
  • 处理流/包装流使用了装饰器设计模式,不会直接与数据源相连

4.3、优点

  • 性能的提高:主要以增加缓冲的方式来提高输入输出的效率
  • 操作的便捷:处理流提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

4.4、常用类

  • BufferedInputStream 字节输入缓冲流
  • BufferedOutputStream 字节输出缓冲流
  • BufferedReader 字符输入缓冲流
  • BufferedWriter 字符输出缓冲流
4.4.1、BufferedInputStream
public static void bufferedInput() throws IOException {
    BufferedInputStream bufferedInputStream = null;
    int charDate;
    byte[] bytes = new byte[16];
    try {
        bufferedInputStream = new BufferedInputStream(new FileInputStream("e:\\test.txt"));
        while ((charDate = bufferedInputStream.read(bytes)) != -1) {
            System.out.print(new String(bytes,0,charDate));
            System.out.println();
            System.out.println(charDate);
        }
    } catch (IOException e) {

    } finally {
        bufferedInputStream.close();
    }
}
4.4.2、BufferedOutputStream
public static void copyFile() throws IOException {
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        bis = new BufferedInputStream(new FileInputStream("e:\\hello.txt"));
        bos = new BufferedOutputStream(new FileOutputStream("e:\\hi.txt"));
        // 每次读取的字节大小
        int readLine;
        // 缓冲
        byte[] bytes = new byte[1024];
        while ((readLine = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, readLine);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        bis.close();
        bos.close();
    }
}
4.4.3、BufferedWriter
public static void bufferedWrite() throws IOException {
    BufferedWriter bufferedWriter = null;
    try {
        bufferedWriter = new BufferedWriter(new FileWriter("e:\\hello.txt"));
        bufferedWriter.write("呵呵,你好!");
        // 当前系统的换行
        bufferedWriter.newLine();
        bufferedWriter.write("呵呵,你好!");
    } catch (IOException e) {

    } finally {
        // 关闭外层缓冲流,该方法内部会自动关闭内部节点流
        bufferedWriter.close();
    }
}

4.5、ObjectInputStream

4.5.1、序列化和反序列化概念
  • 序列化就是在保存数据时,既保存数据的值又保存数据的类型
  • 反序列化就是在数据恢复为对象时,既能恢复数据的值又能恢复数据的类型
    重要:需要让某个对象支持序列化机制,则必须让其类是可序列化的,所以该类必须实现两个接口之一:
  • Serializable
    • 推荐实现该接口,因为该接口为标记接口(接口中没有声明任何方法)
  • Externalizable
4.5.2、序列化
  • 读文件和写文件的顺序必须保持一致
  • 实现可序列化的类必须实现两个序列化接口之一
  • 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
  • 序列化对象时,默认将所有属性进行序列化。但static和transient修饰的成员变量除外
  • 序列化对象时,要求对象的所有属性都需要实现序列化接口(基本数据类型自动装箱为包装类)
  • 序列化具有可继承性,父类实现了序列化,其所有子类也会默认实现序列化
// 基本数据类型的包装类都实现了Serialazable序列化接口
public static void oW() throws IOException {
    ObjectOutputStream oos = null;
    try {
        // 写入数据的顺序同读取的顺序需一致
        oos = new ObjectOutputStream(new FileOutputStream("e:\\data.sss"));
        oos.writeInt(100);
        oos.writeBoolean(true);
        oos.writeChar('a');
        oos.writeDouble(9.232);
        oos.writeUTF("该类型为String");
        oos.writeObject(new BeanDefinition("bean定义"));
    } catch (IOException e) {

    } finally {
        oos.close();
    }
}
4.5.3、反序列化
public static void oI() throws IOException {
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream("e:\\data.sss"));
        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());
        // 该类必须实现可序列化接口
        System.out.println("ois.readObject() = " + ois.readObject());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        ois.close();
    }
}

4.6、转换流

  • 字节流转换为字符流,常用于读写文本
// 将文件字节输入流转为字符输入流,并可指字符编码
public static void ir() throws IOException {
    String filePath = "e:\\hello.txt";
    InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "UTF-8");
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    String s = "";
    while (StringUtils.isNotBlank(s = bufferedReader.readLine()))
        System.out.println(s);
    bufferedReader.close();
}

// 将文件字节输出流转换为字符输出流,并指定输出字符编码
public static void iw() throws IOException {
    String filePath = "e:\\hello.txt";
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath,true),"UTF-8");
    BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
    bufferedWriter.write("我是老赵,我不想和老王做邻居");
    bufferedWriter.close();
}

4.7、标准输入、输出流

  • System.in 输入流 ,类型为InputStream,默认输入设备键盘
  • System.out 输出流,类型为PrintStream,默认输出位置显示器

4.8、打印流

  • 打印流只有输出流,没有输入流
  • PrintStream字节打印流、PrintWriter字符打印流
public static void ps() throws IOException{
    PrintStream printStream = System.out;

    // print底层调用的也是write方法,两者意义相同
    printStream.print("我是老王");
    printStream.write("我是老王".getBytes());

    // 标准输出流默认输出位置是显示器,也可修改其输出位置到文件中
    System.setOut(new PrintStream("e:\\hi.txt"));
    // 修改输出位置后,该输出将写入到文本中
    System.out.println("我是老王啊");
}

public static void pw() throws IOException{
    PrintWriter printWriter = new PrintWriter(new FileOutputStream("e:\\hi.txt"));
    printWriter.print("hi,我是老王");
    printWriter.close();
}

5. Properties类

5.1、继承关系

java.util.properties继承自java.util.Hashtable<Object,Object>

5.2、作用

  • 专门用于读写配置文件的集合类
    • 配置文件格式:键=值
    • 注意:键值对不需要有空格,值不需要用引号,默认类型为String

5.3、常用方法

  • load:加载配置文件的键值对到Properties对象
  • list:将Properties中的数据遍历显示到指定设备
  • getProperty(key):根据键获取值
  • setProperty(key,value):设置键值对到Properties对象
  • store:将Properties中的键值对存储到配置文件,如果含有中文,会存储为unicode码
public static void pw() throws IOException{
    PrintWriter printWriter = new PrintWriter(new FileOutputStream("e:\\hi.txt"));
    printWriter.print("hi,我是老王");
    printWriter.close();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值