JAVA-IOの流れを詳しく解説

1. フロー概要

1.1. IOとは何ですか

IO:入出力とは入力と出力を意味し、流れ(川、水の流れ)とも呼ばれ、データがある場所から別の場所に移動する過程を指し、コンピュータではファイルのコピー処理、ファイルの書き込みと保存、表示機能がこれにあたります。すべての IO が使用され、データ送信プロセスは入力と出力とみなされます。実用的な観点から見ると、耳を入力ストリームとして使用し、口を出力ストリームとして使用できます。

  • 入力および出力メディア:
    • 書類
    • 通信網
    • キーボード入力)
    • 表示(出力)

1.2. IO の分類

Java は、IO 操作に対応する API を提供します。Java のほとんどすべての IO 操作では、パッケージの使用が必要ですjava.io。Java でのストリームの分類には、さまざまな方法が含まれます。

  • フローの方向による分割(通常、入力プロセスと出力プロセスはプログラムの観点から考慮されます)
    • 入力ストリーム (入力)
    • 出力
  • ストリーム処理の種類に応じて
    • バイトストリーム(バイト)
    • 文字ストリーム (char)
  • 流れの働きに従って
    • ノード フロー (入力ソースおよび出力ソースと直接対話する)
    • 処理ストリーム (他のストリームをラップするストリーム: ラッピング ストリーム)

ここに画像の説明を挿入します

1.3. 最上位の親クラス

ストリームにはさまざまなコンテンツがありますが、それらは非常に規則的であり、ほとんどすべてのストリームは次の 4 つの基本ストリームを継承します。

入力ストリーム 出力ストリーム
バイトストリーム java.io.InputStream java.io.OutputStream
文字ストリーム java.io.Reader java.io.Writer

上記の 4 つのストリームは、すべての Java ストリームの最上位の親クラスであり、すべて抽象クラスです。

ストリーム タイプの識別は非常に規則的です。通常、Streamで終わるストリームはバイト ストリームであり、一般に でReader/Writer終わるストリームは文字ストリームです。

1.4. 使用シナリオ

  • ファイルコピー(ファイル)
  • ファイルのアップロードとダウンロード
  • Excelのインポートとエクスポート
  • ネットワークプログラム(チャットツール)でのデータ送信

2. バイトストリーム

2.1. バイトの概要

コンピュータシステムでは、すべてがバイトです。システムに保存されているさまざまなファイル(テキストドキュメント、画像、ビデオ、オーディオ)は、コンピュータの下位レベルにバイトの形式で保存されているため、あらゆるファイル操作に対してすべての操作が可能です1 バイト (読み取り、書き込み) ; java.io のバイト ストリームの最上位の親クラスは次のとおりですInputStream/OutputStream

2.2. バイト入力ストリーム

Java のバイト入力ストリームはすべて からjava.io.InputStream継承されます。このクラスは抽象クラスであるためインスタンス化できません。そのため、jdk はバイト入力に直接使用できるいくつかのサブクラスを提供します。

  • FileInputStream
  • ByteArrayInputStream
  • BufferedInputStream
  • ObjectInputStream

InputStream の一般的なメソッド

  • int available(): ストリーム内の読み取り可能なバイト数を取得します。
  • int read(): ストリームからバイトを読み取り、現在読み取っているバイトデータを返します。
  • int read(byte[] b): 読み取ったバイトデータをバイトバッファに格納し、実際に読み取った総バイト数を返します。
  • skip(int b):次の読み取りのために指定されたバイトをスキップします

2.2.1. ファイル入力ストリーム

FileInputStream主にファイルの読み込みに使用されるバイト入力ストリームの実装ストリームであり、内部メソッドは主に親クラスの実装に使用されます。

  • 共通コンストラクター

    • FileInputStream(File file):提供されたファイルから構築されたオブジェクト
    • FileInputStream(String filePath): 指定されたファイル パスに基づいてオブジェクトを構築します
  • FileInputStreamファイルの読み取りに使用します

    1. 基本読み取り (一度に 1 バイトずつ読み取り)

      //创建File对象
      File file = new File("C:\\Users\\Administrator\\Desktop\\新建文本文档.txt");
      //基于File创建字节输入流
      InputStream in = new FileInputStream(file);
      
      //读取一个字节
      int i = in.read();
      System.out.println((char)i);
      

      Java の IO は標準ファイルの読み取りと書き込みのみが可能であり、ディレクトリの入力ストリームまたは出力ストリームを直接作成することは許可されていません (これにより、 が発生しますjava.io.IOException(拒绝访问))。

    2. バイトバッファを使用して読み取ります(バッファサイズは読み取り可能な合計バイト数です)

      上記の読み取り方法は 1 バイトずつ読み取るため、読み取り効率が非常に低いため、実際の開発では、読み取り効率を向上させるためにバイト バッファーが一般的に使用されます。

      //创建File对象
      File file = new File("C:\\Users\\Administrator\\Desktop\\新建文本文档.txt");
      //基于File创建字节输入流
      InputStream in = new FileInputStream(file);
      
      //创建字节缓冲区(大小为总可读字节数)
      byte[] arr = new byte[i];
      //将流中读取的字节内容存储到数组中
      int total = in.read(arr);
      //将字节数组转换为String字符串
      System.out.println(new String(arr));
      
    3. 適切なサイズのバイトバッファを使用して読み取ります

      上記の読み込みは、ファイル内のデータを一度にバッファに読み込むため、バッファの容量が非常に大きくなる場合があり、大きなファイルを読み込むために大きすぎるバッファを使用すると問題が発生する可能性があります。スペースを消費し、他のプログラムの実行に影響を与えるため、繰り返し読み込むには適切なサイズのバッファが必要です。

      //创建文件输入流对象(文件:一缸水)
      InputStream in = new FileInputStream("C:\\Users\\Administrator\\Desktop\\Hero.java");
      
      //创建缓冲区(购买一个大小适中的水桶)
      byte[] b = new byte[1024];
      //声明临时变量表示每次读取的实际字节数
      int len = 0;
      while((len = in.read(b)) != -1){
              
              
          String s = new String(b,0,len);
          System.out.println(s);
      }
      

      上記の読み取り方法は、バイトストリームで読み取るための従来のソリューションです。

2.3. バイト出力ストリーム

データの流れの方向に応じた読み取り (入力) 操作に加えて、データの書き込み (出力) 操作も非常に一般的です。Java のバイト出力ストリームはjava.io.OutputStream

OutputStreamこれは抽象クラスでありインスタンス化できないため、jdk はこのストリームのサブクラスも提供します。

  • FileOutputStream
  • ByteArrayOutputStream
  • BufferedOutputStream
  • ObjectOutputStream
  • PrintStream

OutputStream クラスの一般的なメソッド:

  • write(int b): 出力ストリームを通じてターゲット出力ソースにバイトを書き込みます。
  • write(byte[] b): 出力ストリームを通じてターゲット出力ソースにバイト配列を書き込みます。
  • write(byte[] b,int offset,int len)配列のオフセットから始まる len バイトをターゲット出力ソースに書き込みます

2.3.1. ファイル出力ストリーム

FileOutputStreamこれはバイト出力ストリームの実装ストリームであり、主にファイルの書き込みに使用され、内部メソッドは主に親クラスの実装に使用されます。

  • 一般的なコンストラクター

    • FileOutputStream(String filePath): 標準のファイル パスに基づいて操作する出力ストリームを作成します。
    • FileOutputStream(String filePath,boolean append): 追加モードを使用して、標準ファイル パス上で動作する出力ストリームを作成します。
    • FileOutputStream(File file): 標準のファイル パスに基づいて操作する出力ストリームを作成します。
    • FileOutputStream(File file,boolean append)追加モードを使用して、標準ファイル オブジェクトを操作する出力ストリームを作成する
  • FileOutputStreamファイルの書き込みに使用します

     //try...with语句:JDK1.7
            //针对所有的第三方资源不再需要手动回收(关闭)
            //因为从jdk1.7开始,很多资源类都实现过Closeable接口,但凡实现过该接口类
            //只要将其在try()中创建,不再手动关闭资源,会由JVM自动回收
            try(OutputStream os = new FileOutputStream("readme.txt",true);){
          
          
                //写出一个字节到文件中
    //            os.write(101);
    
                //荀子·劝学篇
                String msg = "不积小流无以成江海,不积跬步无以至千里";
                os.write(msg.getBytes());
    
            }catch (IOException e){
          
          
                e.printStackTrace();
            }
    

2.4. 包括的な事件ファイルのコピー

/**
     * 将一个源文件拷贝到一个目标目录中
     * @param src 源文件
     * @param targetDir 目标目录
     */
public static void copyFile(File src, File targetDir) throws IOException {
    
    
    InputStream is = null;
    OutputStream os = null;
    try {
    
    
        //获取源文件的输入流
        is = new FileInputStream(src);
        //获取目标文件的输出流(目标文件是由:目录+源文件名称构成):文件输出流可以创建文件(前提:父目录必须存在)
        os = new FileOutputStream(new File(targetDir,src.getName()));
        //声明字节缓冲区(缓冲区越大,拷贝效率越高,但是带来空间损耗也越大)
        byte[] b = new byte[1024*1024];
        //临时变量表示实际读取的字节数
        int len = 0;
        System.out.println("开始拷贝...");
        while((len = is.read(b)) != -1){
    
    
            //写出读取的内容到输出流
            os.write(b,0,len);
        }
        System.out.println("拷贝完成!");
    }  finally{
    
    
        if(os != null){
    
    
            os.close();
        }
        if(is != null){
    
    
            is.close();
        }
    }

}

//测试
public static void main(String[] args) throws IOException {
    
    
    //源文件
    File src = new File("D:\\素材\\视频\\短视频\\test.mp4");
    //目标目录
    File targetDir = new File("C:\\Users\\Administrator\\Desktop");
    //文件拷贝
    copyFile(src,targetDir);
}

ファイル コピーに基づいてディレクトリ コピーを実装します。

public class FileCopy {
     
     

/**
   * 将一个源目录拷贝到另一个目标目录中
   * @param srcDir
   * @param targetDir
   */
  public static void copyDir(File srcDir,File targetDir) throws IOException {
     
     
      //获取新目录对象
      targetDir = new File(targetDir,srcDir.getName());
      //如果新目录不存在,则创建
      if(!targetDir.exists()){
     
     
          targetDir.mkdirs();
      }
      File[] files = srcDir.listFiles();
      if(Objects.nonNull(files)){
     
     
          for (File file : files) {
     
     
              if(file.isDirectory()){
     
     
                  //目录递归拷贝
                  copyDir(file,targetDir);
              }else{
     
     
                  //执行文件拷贝
                  copyFile(file,targetDir);
              }
          }
      }
  }

  /**
   * 将一个源文件拷贝到一个目标目录中
   * @param src 源文件
   * @param targetDir 目标目录
   */
  public static void copyFile(File src, File targetDir) throws IOException {
     
     
      InputStream is = null;
      OutputStream os = null;
      try {
     
     
          //获取源文件的输入流
          is = new FileInputStream(src);
          //获取目标文件的输出流(目标文件是由:目录+源文件名称构成)
          os = new FileOutputStream(new File(targetDir,src.getName()));
          //声明字节缓冲区(缓冲区越大,拷贝效率越高,但是带来空间损耗也越大)
          byte[] b = new byte[1024*1024];
          //临时变量表示实际读取的字节数
          int len = 0;
          System.out.println("开始拷贝...");
          while((len = is.read(b)) != -1){
     
     
              //写出读取的内容到输出流
             os.write(b,0,len);
          }
          System.out.println("拷贝完成!");
      }  finally{
     
     
          if(os != null){
     
     
              os.close();
          }
          if(is != null){
     
     
              is.close();
          }
      }

  }

  public static void main(String[] args) throws IOException {
     
     
      //源目录
      File srcDir = new File("D:\\素材\\视频");
      //目标目录
      File targetDir = new File("C:\\Users\\Administrator\\Desktop\\video");
      //目录拷贝
      copyDir(srcDir,targetDir);
  }
}

3. 文字ストリーム

3.1. キャラクター概要

通常、 では文本文件、ファイル コンテンツは通常、GBK エンコーディング モードで文字 (漢字、英語の文字、記号) の形式で存在します。文字ストリームは通常、テキスト データの処理に適しています。Java のほとんどすべての文字ストリーム1个字符=2个字节Reader/Writer、そしてすべては 2 つの基本的な抽象クラスを継承します。

  • java.io.Reader:文字入力ストリーム
  • java.io.Writer:文字出力ストリーム

3.2. 文字入力ストリーム

文字入力ストリームは通常、テキスト データ、一般的なサブクラスを読み取るために使用されます。

  • InputStreamReader
  • FileReader
  • BufferedReader
  • CharArrayReader

3.2.1. ファイルリーダー

FileReader は、ファイル コンテンツを文字ストリームの形式で読み取るストリームです。FileReaderInputStreamReaderから継承されており、冗長な内部メソッドはありません (親クラスの API と一貫性があります)。次の一般的な構築メソッドが提供されます。

  • 一般的な工法

    • FileReader(File file): 提供されたファイル オブジェクトに基づいてファイル文字入力ストリームを取得します
    • FileReader(String path):指定されたファイルパスに基づいてファイル文字入力ストリームを取得します
  • 具体的な用途

    //创建文件字符输入流
    FileReader fr = new FileReader("D:\\文档资料\\电子书\\书籍推荐.txt");
    
    //获取当前流使用的默认编码模式(并非目标文件的编码)
    //        String encoding = fr.getEncoding();
    //        System.out.println(encoding);
    
    //读取一个字符(以int类型存在)
    //        int read = fr.read();
    //        System.out.println((char)read);
    
    //        int c = 0;
    //        while((c = fr.read()) != -1)
    //        {
          
          
    //            System.out.print((char)c);
    //        }
    
    //使用字符缓冲区
    char[] ch = new char[100];
    int len = 0;
    while((len = fr.read(ch)) != -1){
          
          
        String s = new String(ch,0,len);
        System.out.print(s);
    }
    

3.3. 文字出力ストリーム

文字出力ストリームは通常、テキスト データを書き込むために使用されます。

  • 読者`
  • OutputStreamWriter
  • BufferedWriter
  • CharArrayWriter
  • FileWriter
  • PrintWriter

3.3.1 ファイルライター

FileWriter は、ファイル コンテンツを文字ストリームの形式で書き込むストリームです。FileWriter から継承されており、OutputStreamWriter冗長な内部メソッドはありません (親クラスの API と一貫性があります)。次の一般的な構築メソッドが提供されます。

  • 一般的な工法

    • FileWriter(File file): 提供されたファイル オブジェクトに基づいてファイル文字入力ストリームを取得します
    • FileWriter(String path):指定されたファイルパスに基づいてファイル文字入力ストリームを取得します
    • FileWriter(File file,boolean append): 提供されたファイル オブジェクトに基づいてファイル文字入力ストリームを取得します (追加モードを使用)
    • FileWriter(String path,boolean append): 指定されたファイル パスに基づいてファイル文字入力ストリームを取得します (追加モードを使用)
  • 具体的な用途

    //基于指定的文件创建字符输出流
    FileWriter fw = new FileWriter("readme.txt");
    fw.write("路漫漫其修远兮,吾将上下而求索");
    
    //允许在流未关闭之前,强制将字符缓冲区中的数据写出到目标输出源
    fw.flush();
    
    Thread.sleep(10000);
    fw.write("好好xio习,天天up!!!");
    fw.close();
    

    文字出力ストリームの場合、1 つは内部的に使用されます字符缓冲区(字符数组)。データを書き込むとき、書き込まれるデータは通常文字配列にキャッシュされ、ストリームが閉じられると (またはバッファがいっぱいになると)、バッファは 1 つのストリームにキャッシュされます。文字バッファー内のデータはターゲット出力ソースに書き出されます。ストリームが閉じる前 (またはバッファーがいっぱいでないとき) に文字バッファー内のデータを強制的に書き出す必要がある場合は、手動で行うことができます。強制出力を呼び出しますflush()

4. 処理の流れ

ストリームの処理タイプ (機能) は、ノード ストリームと処理ストリームに分けられます。

  • ノードフロー

    低レベル ストリームとも呼ばれ、入出力ソースと直接通信するストリーム (例: FileReader、FileWriter、FileInputStream、FileOutputStream)

  • 処理の流れ

    処理フローは、アドバンスト フローまたはパッケージング フローと类型转换も呼ばれ、他のノード フローをラップしてフローや効率の向上を実現するために使用できます。処理の流れは主に缓冲流とで转换流構成されます。

パッケージングには通常、デザインパターン(デコレータパターン)が使用されます。

4.1. バッファリングされたストリーム

バッファ付きストリームとは独自のバッファを持つストリームで、主に次の 4 種類で構成されます。

  • BufferedInputStream: バイトバッファされた入力ストリーム
  • BufferedOutputStream: バイトバッファされた出力ストリーム
  • BufferedReader: 文字バッファリングされた入力ストリーム
  • BufferedWriter: 文字バッファリングされた出力ストリーム
long start = System.currentTimeMillis();
try(
    //获取输入流
    InputStream in = new FileInputStream("D:\\集团资料\\宣讲\\video\\云计算&大数据\\阿里云.mp4");
    //包装节点流
    BufferedInputStream bis = new BufferedInputStream(in);
    //获取输出流
    OutputStream os = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\阿里云.mp4");
    //包装节点流
    BufferedOutputStream bos = new BufferedOutputStream(os);
) {
    
    
    System.out.println("开始拷贝");
    byte[] b = new byte[1024*1024*8];
    int len = 0;
    while((len = bis.read(b)) != -1){
    
    
        bos.write(b,0,len);
    }
    System.out.println("拷贝结束");
}catch (IOException e){
    
    
    e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start));

バッファリングされたストリームの内部実装原理では8kb、デフォルト サイズのバイト バッファが使用されます。バッファ スペースがいっぱいになるたびに、データはストリーム オブジェクトを通じて読み書きされます。

4.2. 変換ストリーム

要件によっては、バイト ストリームのデータを文字ストリームに変換する必要がある場合や、文字ストリームをバイト ストリームに変換する必要がある場合があり、この場合、関数を完了するために変換ストリームを使用する必要があります。変換ストリームは通常、次のファイルで使用されます。 トランスコーディング、ネットワークから読み取られたデータがバイト ストリームであるが、ストリームに含まれるコンテンツが文字である場合、変換ストリームを使用して変換を実行できます。Java の変換ストリーム。 io は主に次の 2 つのクラスで構成されます。

  • InputStreamReader: バイト入力ストリームを文字入力ストリームに変換するために使用されます (バイト -> 文字)
  • OutputStreamWriter: 文字出力ストリームをバイト出力ストリームに変換するために使用されます (文字 -> バイト)

使用例:

//获取标准输入流
InputStream is = System.in;

//将字节流转换为字符流
Reader isr = new InputStreamReader(is);
//将字符节点流包装为缓冲流
BufferedReader br = new BufferedReader(isr);
//读取一行
String line = br.readLine();
System.out.println("输入的内容--->"+line);

ここに画像の説明を挿入します

ストリームの変換では、ストリームの種類のみが変換でき、ストリームの方向は変換できません。

4.3. 包括的なケース: ファイルトランスコーディングツール

日常的なファイル コピーでは、複数のエディタ (システム) のエンコード モードの違いにより、ファイルが文字化けする問題が発生する可能性が非常に高くなります (テキスト ファイルの場合によく発生します)。ファイル トランスコーディングの機能は、ストリームを変換することで実現できます。

public class FileCharacterConvert {
    
    

    /**
     * 将一个目标文件的编码转换为新的编码
     * @param file  原始文件
     * @param targetDir 目标目录
     * @param oldEncoding  原始编码
     * @param newEncoding   新编码
     */
    public static void convert(File file,File targetDir, String oldEncoding, String newEncoding) throws IOException {
    
    

        //使用特定的编码获取文件的输入流
        FileInputStream fis = new FileInputStream(file);
        Reader reader = new InputStreamReader(fis,oldEncoding);
        BufferedReader br = new BufferedReader(reader);

        //使用特定的编码获取文件的输出流
        FileOutputStream fow = new FileOutputStream(new File(targetDir,file.getName()));
        Writer writer = new OutputStreamWriter(fow,newEncoding);
        BufferedWriter bw = new BufferedWriter(writer);

        //开始读写
        String line = "";
        //循环读取每一行文本以换行符作为一行的结束标记(但是换行符不会被作为内容读取)
        while((line = br.readLine()) != null){
    
    
            //写入读取的一行文本()
            bw.write(line);
            //手动加入一个换行标记到文件,否则所有内容会在同一行显示
            bw.newLine();
            //将缓冲区的数据强制输出到目标输出源
            bw.flush();
        }
        bw.close();
        br.close();
    }

    public static void main(String[] args) throws IOException {
    
    
        //准备需要转换的文件
        File f = new File("C:\\Users\\Administrator\\Desktop\\GamePanel.java");
        convert(f,new File("C:\\Users\\Administrator\\Desktop\\temp"),"gbk","utf-8");
    }
}

5. 印刷ストリーム

java.io は、データ出力用に 2 つの特別なストリームを提供します: 印刷ストリームです。印刷ストリームには出力のみがあり、入力はありません。出力ソース用に直接作成することも、他の出力ストリームをパッケージ化することもできます。印刷ストリームには主に次の 2 つのストリームが含まれます. :

  • PrintStream: バイト印刷ストリーム
  • PrintWriter: 文字印刷ストリーム

5.1. プリントストリーム

PrintStreamから継承されjava.io.OutputStream、バイト データ出力に使用されるストリームであり、多数のprint/prinlnオーバーロードされたメソッドが含まれており、System.out実際にはPrintStream

  • 共通コンストラクター

    • PrintStream(File file): 指定されたファイルに基づいて印刷ストリームを作成します
    • PrintStream(OutputStream os): 他のバイト出力ストリームをラップします。
    • PrintStream(OutputStream os,boolean autoFlush): 他のバイト出力ストリームをラップし、ストリーム内のデータを自動的に更新できます。
  • 一般的な方法

    • print(...)
    • println(...)
  • 基本的な使い方

    //        PrintStream ps = new PrintStream(new File("readme.txt"),true);
    
    OutputStream os = new FileOutputStream("readme.txt", true);
    PrintStream ps = new PrintStream(os,true);
    ps.println("你好中国");
    

5.2. プリントライター

PrintWriter違いPrintStreamは、PrintWriterこれが文字ベースの印刷ストリーム (文字バッファーを含む) であり、その API が とPrintStream非常に似ていることです。PrintWriter印刷データを使用する場合は必ずflush()メソッドを実行してください。

FileWriter fw = new FileWriter("readme.txt",true);

PrintWriter pw = new PrintWriter(fw);

pw.println("哪里有彩虹告诉过我!!!");

pw.flush();

pw.close();

6. リソースファイルの読み込み(Propertiesクラス)

フレームワークの後の学習プロセスでは、いくつかの構成ファイルの作成がしばしば関係します。プロパティ ファイルは非常に一般的なファイル タイプです。Java は、プロパティ ファイルの読み取りと書き込みのためのクラスを提供しますjava.util.Properties

InputStream in = PropertiesDemo.class.getResourceAsStream("/jdbc.properties");
//创建属性对象
Properties prop = new Properties();
//        Properties prop = System.getProperties();
//加载流到属性对象中
prop.load(in);

String user = prop.getProperty("user");
String url = prop.getProperty("url");
System.out.println(user);
System.out.println(url);

prop.setProperty("maxActive","10");

File f = new File("D:\\带班资料\\2021\\J2106\\课程资料\\code\\part1-javase\\java高级\\lesson_01_IO\\resources\\jdbc.properties");
FileWriter fw = new FileWriter(f);
prop.store(fw,"this is jdbc config file");
fw.close();

7. 流れの概要

  • すべての入力ストリーム名には、 が含まれますinputread
  • すべての出力ストリーム名には、 が含まれますoutputwrite
  • すべてのバイト ストリーム名は次でstream終わります。
  • すべての文字ストリーム名はreaderorでwriter終わります
  • 一般に、バイナリタイプのファイル(テキストドキュメントを使用して直接開くことができない画像、ビデオ、オーディオ、圧縮ファイルなど)は主にバイトストリーム操作を使用します。
  • 一般的なテキスト タイプのファイル (txt、md、java、およびテキスト ドキュメントを使用して直接開くことができるその他のファイル) は、主に文字ストリーム操作を使用します。

おすすめ

転載: blog.csdn.net/weixin_48006490/article/details/126649763