数据源

  • 数据源即data source,提供数据的原始媒介。常见数据源有:数据库、文件、其他程序、内存、网络连接、IO设备
  • 数据源分为:源设备、目标设备。源设备为程序提供数据,一般对应输入流;目标设备是程序数据的目的地,一般对应输出流。

  • 流是抽象、动态的概念,是一连串连续动态的数据集合。

  • 对于输入流。数据源就像水箱,流像水管中流动的水流,程序是最终的用户。通过流stream将数据源source中的数据information输送到程序program中。
  • 对于输出流,目标数据源就是目的地dest,我们通过流将程序中的数据输送到目的数据源中。
  • 输入输出流的划分是相对程序而言的,并不是相对数据源

    流概念细分

    流的方向

  • 输入流:数据流向是数据源到程序(InputStream、Reader结尾的流)

  • 输出流:数据流向是程序到目的地(OutputStream、Writer结尾的流)

    处理的数据单元

  • 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。

  • 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter,一般用于处理txt文本文件

    处理对象

  • 节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等

  • 处理流:不直接连接到数据或目的地,是“处理其他流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等

image.png

IO流的体系

IO流 - 图2

文件字符流

  • 文件字节流可以处理所有的文件,但是字节流不能很好的处理Unicode字符,经常出现乱码情况。所以处理文本文件,一般可以使用文件字符流,它以字符为单位进行操作。

    1. FileReader fr = new FileReader("/d.txt");
    2. FileWriter fw = new FileWriter("/d_copy.txt")

    缓冲字节流

  • Java缓冲流本身不具备IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能以提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。

  • 当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地,在IO操作时加上缓冲流可以提高性能。
  • BufferedInputStream和BufferedOutputStream这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。

    1. FileInputStream fis = new FileInputStream("/img.png");
    2. FileOutputStream fos = new FileOutputStream("/img_copy.png");
    3. BufferedInputStream bis = new BufferedInputStream(fis);
    4. BufferedOutStream bos = new BufferedOutputStream(fos);

    缓冲字符流

  • BufferedReader/BufferedWriter增加了缓存机制,大大提高了读写文本文件的效率,同时提供了更方便的按行读取的方法:readLine();处理文本时,我们一般可以使用缓冲字符流。 ```java try( BufferReader br = new BufferReader(new FileReader(“/d.txt”));

    1. BufferWriter bw = new BufferWriter(new FileWriter("/d2.txt"));

    ){

    String tempString = “”; while((tempString = br.readLine) != null){

    1. bw.write(tempString);
    2. bw.newLine();

    } }

  1. <a name="hDORV"></a>
  2. ### 字节数组流
  3. - ByteArrayInputSream和ByteArrayOutputStream经常用在需要流和数组之间转化的情况,与FileInputStream把文件当作数据源不同,ByteArrayInputStream把内存中的某个字节数组对象当作数据源
  4. ```java
  5. ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes[])

数据流

  • 将基本数据类型与字符串类型作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作java基本数据类型与字符串类型。
  • DataInputStream和DataOutputStream提供了可以存取与机器无关的所有java基础类型数据(如int、double、String等)
  • DataInputStream和DataOutputStream时处理流,可以对其他节点流和处理流进行包装,使得更灵活、高效 ```java try(DataOutputStream dos = new DataOutputStream(new FileOutputStream(“/data.txt”))){ dos.writeChar(‘a’); dos.writeInt(10); dos.writeDouble(Math.random()); dos.writeBoolean(true); dos.writeUTF(“程序员”); dos.flush(); // 手动刷新缓冲区,流中数据写入文件中 }catch…

try(DataInputStream dis = new DataInputStream(new FileIntputStream(“/data.txt”))){ // 读取数据与写入数据顺序保持一致,否则无法正确读取 dis.readChar(‘a’); dis.readInt(10); dis.readDouble(Math.random()); dis.readBoolean(true); dis.readUTF(); }catch…

  1. <a name="rBwtv"></a>
  2. ### 对象流和序列化/反序列化
  3. - ObjectInputStream/ObjectOutputStream是以“对象”为数据源,但是必须将传输的对象进行序列话与反序列化操作。
  4. - 需要序列化的对象,需要实现java.io.Serializable(标记接口)
  5. - 对象序列化的作用有
  6. - 持久化:把对象的字节序列永久的保存在硬盘上,通常存放在一个文件中,比如休眠的实现,以后服务器session管理,hibernate将对象持久化实现
  7. - 网络通信:在网络上传送对象的字节序列。比如服务器之间的数据通信、对象传递。
  8. <a name="L3vDt"></a>
  9. ### ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1683338/1647164095816-43e30d39-3886-4c99-8e1f-d3c3e5234671.png#clientId=u58756fe4-7cc1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=164&id=u93ea82f8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=970&originWidth=2988&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1012625&status=done&style=none&taskId=u2117582b-97fe-4752-8183-3a1f3946563&title=&width=506)
  10. - static属性不参与序列化,对象中的某些属性如果不想被序列化,不能使用static,用**transient**修饰
  11. ```java
  12. public class User implements java.io.Serializable{
  13. private int id;
  14. private String uname;
  15. transient private String pwd;
  16. // constructor...
  17. // getter\setter...
  18. }
  19. class Test{
  20. public static void main(String[] agrs){
  21. writeObj();
  22. readObj();
  23. }
  24. public static void writeObj(){
  25. try(ObjectOutputStream = new ObjectOutputStream(new FileOutputStream("/obj.txt"))){
  26. ArrayList<User> list = new ArrayList<>();
  27. list.add(new User(1001,"bob","123"));
  28. list.add(new User(1002,"boo","231"));
  29. list.add(new User(1003,"bbo","321"));
  30. oos.writeObject(list);
  31. oos.flush();
  32. }catch...
  33. }
  34. public static void readObj(){
  35. try(ObjectInputStream = new ObjectInputStream(new FileInputStream("/obj.txt"))){
  36. ArrayList<User> list = (ArrayList)ois.readObject;
  37. for(User u:list){
  38. System.out.println(u.getId()...)
  39. }
  40. // 但是密码时空的,不参与序列化
  41. }catch...
  42. }
  43. }

转换流

  • InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流

    1. try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    2. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    3. ){
    4. String str = br.readLine();
    5. while(!"exit".equals(str)){
    6. bw.write("键盘输入," + str);
    7. bw.newLine();
    8. bw.flush();
    9. str = br.readLine();
    10. }
    11. }

    image.png

    随意访问文件流

  • RandomAccessFile可以实现

    • 对一个文件做读和写的操作
    • 可以访问文件的任意位置。不想其他流只能按照先后顺序读取

      1. try(RandomAccessFile raf = new RandomAccessFile("/a.txt","rw")){
      2. int[] data = {10, 20, 30, 40, 50};
      3. for(int i =0; i<data.legth;i++){
      4. raf.writeInt(data[i]);
      5. }
      6. // 从第4个字节开始读,跳过一个整数,20
      7. raf.seek(4);
      8. sout(raf.readInt());
      9. // 30换成45
      10. raf.seek(8);
      11. raf.writeInt(45);
      12. }

      IO流程序模板

  • 分别使用try-catch-finally、try-with-resource两种结构写经典的io字节流程序 ```java package bosoftware;

import java.io.*;

public class test01 { public static void main(String[] args) { readFile(); writeFile(); copyFile(“/Users/bomb/LearningSpace/JavaBasic/Practise/files/sinopec.jpeg”,”/Users/bomb/LearningSpace/JavaBasic/Practise/files/sinopec_copy.jpeg”); }

  1. public static void readFile() {
  2. FileInputStream fis = null;
  3. try {
  4. fis = new FileInputStream("/Users/bomb/LearningSpace/JavaBasic/Practise/files/a.txt");
  5. int temp = 0;
  6. StringBuilder sb = new StringBuilder();
  7. while ((temp = fis.read()) != -1) {
  8. sb.append((char)temp);
  9. }
  10. System.out.println(sb);
  11. } catch (FileNotFoundException e) {
  12. e.printStackTrace();
  13. } catch (IOException e) {
  14. e.printStackTrace();
  15. } finally {
  16. try {
  17. if (fis != null) {
  18. fis.close();
  19. }
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. public static void writeFile() {
  26. try (FileOutputStream fos = new FileOutputStream("/Users/bomb/LearningSpace/JavaBasic/Practise/files/b.txt")) {
  27. fos.write("fuck java".getBytes());
  28. } catch (FileNotFoundException e) {
  29. e.printStackTrace();
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. public static void copyFile(String srcpath,String destpath) {
  35. try ( FileInputStream fis = new FileInputStream(srcpath);
  36. FileOutputStream fos = new FileOutputStream(destpath)) {

// int temp = 0; // while ((temp = fis.read()) != -1) { // fos.write(temp); // } byte[] buffer = new byte[1024]; while ((fis.read(buffer)) != -1) { fos.write(buffer); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }

}

  1. <a name="XDjkO"></a>
  2. # Apache IO包
  3. <a name="vuV3c"></a>
  4. ## 装饰器模式构建IO流体系
  5. - 装饰器模式是GOF23种设计模式中较为常用的一种模式。它可以实现对原有类的包装和修饰,使新类具有更强的功能。
  6. - 处理流是用装饰器模式实现的
  7. <a name="REmUo"></a>
  8. ## apche commons的IO类
  9. - [https://commons.apache.org/proper/commons-io/](https://commons.apache.org/proper/commons-io/)
  10. ```java
  11. package com.de;
  12. import org.apache.commons.io.*;
  13. import java.io.File;
  14. import java.io.FileFilter;
  15. import java.io.IOException;
  16. import java.io.InputStream;
  17. import java.net.MalformedURLException;
  18. import java.net.URL;
  19. import java.util.List;
  20. public class TestApacheIOUtils {
  21. public static void main(String[] args) {
  22. StringBuilder sb = new StringBuilder();
  23. for(int i=0;i<1000;i++){
  24. sb.append(Math.random()+"\n");
  25. }
  26. writeFile(sb.toString());
  27. readFile();
  28. readURL();
  29. copyFile();
  30. }
  31. public static void writeFile(String sb) {
  32. try {
  33. FileUtils.write(new File("/Users/bomb/LearningSpace/JavaBasic/Practise/files/c.txt"), sb, "gbk");
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. public static void readFile(){
  39. try {
  40. List<String> content= FileUtils.readLines(new File("/Users/bomb/LearningSpace/JavaBasic/Practise/files/c.txt"),"gbk");
  41. for (String temp:content) {
  42. System.out.println(temp);
  43. }
  44. } catch (IOException e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. public static void copyFile(){
  49. File srcFile = new File("/Users/bomb/LearningSpace/JavaBasic/Practise/files/c.txt");
  50. File destFile = new File("/Users/bomb/LearningSpace/JavaBasic/Practise/files/d.txt");
  51. try {
  52. FileUtils.copyFile(srcFile,destFile);
  53. } catch (IOException e) {
  54. e.printStackTrace();
  55. }
  56. }
  57. public static void copyDirectory() {
  58. File dir1 = new File("/文件夹1");
  59. File dir2 = new File("/文件夹2");
  60. try {
  61. FileUtils.copyDirectory(dir1, dir2, new FileFilter() {
  62. @Override
  63. public boolean accept(File pathname) {
  64. if (pathname.isDirectory() || pathname.getName().endsWith("png")) {
  65. return true;
  66. } else {
  67. return false;
  68. }
  69. }
  70. });
  71. } catch (IOException e) {
  72. e.printStackTrace();
  73. }
  74. }
  75. public static void readURL(){
  76. try {
  77. URL url = new URL("http://www.baidu.com");
  78. InputStream is = url.openStream();
  79. String s = IOUtils.toString(is,"UTF-8");
  80. System.out.println(s);
  81. } catch (MalformedURLException e) {
  82. e.printStackTrace();
  83. } catch (IOException e) {
  84. e.printStackTrace();
  85. }
  86. }
  87. }