記事ディレクトリ
IO ストリームの基本的な紹介
IO ストリームの概要:
I は入力の略で、ハードディスク ファイルからメモリにデータを読み取るプロセスであり、入力と呼ばれ、読み取りを担当します。
Oは出力を意味し、メモリプログラムのデータがメモリからハードディスクファイルに書き出されるまでのプロセスであり、出力と呼ばれ、書き込みを担当します。
IO ストリームの分類:
方向別分類:
- 入力ストリーム
- 出力ストリーム
ストリーム内のデータの最小単位に従って、次のように分割されます。
- バイト ストリーム: すべての種類のファイルを操作できます (オーディオ、ビデオ、スクリーン ピクチャなどを含む) 。
- 文字ストリーム: プレーン テキスト ファイル ( java ファイル、txt ファイルなどを含む)でのみ操作できます。
ストリームの 4 つの主なカテゴリを要約すると、次のようになります。
バイト入力ストリーム: メモリに基づいて、ディスク ファイル/ネットワークからのデータがバイト形式でメモリに読み込まれるストリームは、バイト入力ストリームと呼ばれます。
バイト出力ストリーム: メモリに基づいて、メモリ内のデータをディスク ファイルまたはネットワークにバイト単位で書き込むストリームは、バイト出力ストリームと呼ばれます。
文字入力ストリーム: メモリに基づいて、ディスク ファイル/ネットワークからのデータが文字の形式でメモリに読み込まれるストリームは、文字入力ストリームと呼ばれます。
文字出力ストリーム: メモリに基づいて、メモリ内のデータをディスク ファイルまたはネットワーク メディアに文字で書き込むストリームを文字出力ストリームと呼びます。
バイトストリームの使用
ファイルバイト入力ストリーム
バイト入力ストリームの作成
ファイル バイト入力ストリーム: クラス FileInputStream を実装します。
機能: メモリに基づいて、ディスク ファイル内のデータをバイト単位でメモリに読み込みます。
コンストラクタは次のとおりです。
コンストラクタ | 例証する |
---|---|
public FileInputStream(ファイルファイル) | ソース ファイル オブジェクトに接続するバイト入力ストリーム パイプを作成する |
public FileInputStream(文字列パス名) | ソース ファイル パスに接続されたバイト入力ストリーム パイプを作成する |
サンプルコード:
public static void main(String[] args) throws FileNotFoundException {
// 写法一: 创建字节输入流与源文件对象接通
InputStream inp = new FileInputStream(new File("/file-io-app/src/test.txt"));
}
public static void main(String[] args) throws FileNotFoundException {
// 写法二: 创建字节输入流管道与源文件路径接通
InputStream inp = new FileInputStream("/file-io-app/src/test.txt");
}
一度に 1 バイトずつ読み取る
メソッド名 | 例証する |
---|---|
読む() | 一度に 1 バイトを返すか、読み取るバイトがない場合は -1 を返します。 |
たとえば、読み取ったメモ帳ファイルの内容は次のとおりです。abcd123
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
int a = inp.read();
System.out.println(a); // 97
System.out.println((char) a); // a
// 一次输入一个字节
System.out.println(inp.read()); // 98
System.out.println(inp.read()); // 99
System.out.println(inp.read()); // 100
System.out.println(inp.read()); // 49
System.out.println(inp.read()); // 50
System.out.println(inp.read()); // 51
// 无字节可读返回-1
System.out.println(inp.read()); // -1
}
ファイル内のバイトをループできます
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
int b;
while ((b = inp.read()) != -1) {
System.out.print((char) b); // abcd123
}
}
一度に 1 バイトを読み取るには、次の問題があります。
遅いパフォーマンス
漢字出力を読み取る場合、文字化けの問題は避けられません。
一度に配列を読み取る
メソッド名 | 例証する |
---|---|
読み取り (バイト [] バッファー) | バイト配列が読み取られるたびに、読み取られたバイト数が返され、読み取れるバイトがそれ以上ない場合は -1 が返されます |
読み取ったバイト数を受け取るバイト配列を定義する
たとえば、次のコードでは、ファイルの内容は abcd123 で、毎回 3 バイトが読み取られ、読み取りごとに前の配列の内容が上書きされますが、3 回目の読み取りでは 1 文字しか読み取れないため、最初の読み取りのみが上書きされます。前回読み取った文字配列の要素、結果: 312
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个长度为3的字节数组
byte[] arr = new byte[3];
// 第一次读取一个字节数组
int len1 = inp.read(arr);
System.out.println("读取字节数: " + len1); // 读取字节数: 3
// 对字节数组进行解码
String res1 = new String(arr);
System.out.println(res1); // abc
// 第二次读取一个字节数组
int len2 = inp.read(arr);
System.out.println("读取字节数: " + len2); // 读取字节数: 3
// 对字节数组进行解码
String res2 = new String(arr);
System.out.println(res2); // d12
// 第三次读取一个字节数组
int len3 = inp.read(arr);
System.out.println("读取字节数: " + len3); // 读取字节数: 1
// 对字节数组进行解码
String res3 = new String(arr);
System.out.println(res3); // 312
// 无字节可读返回-1
System.out.println(inp.read()); // -1
}
String の 2 番目のパラメーターで開始位置を指定し、3 番目のパラメーターで終了位置を指定できるため、この 2 つのパラメーターを使用して、3 番目の読み取りの欠点を解決できます。
そしてループは最適化されたコードを改善します
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
byte[] arr = new byte[3];
int len;
while ((len = inp.read(arr)) != -1) {
String res = new String(arr, 0, len);
System.out.print(res); // abcd123
}
}
一度に配列を読み取ることの欠点:
読み取りパフォーマンスが向上しました
漢字出力を読み取る場合、文字化けの問題は避けられません。
一度にすべてのバイトを読み取る
中国語の文字化けの問題を解決するには、ファイルと同じ大きさのバイト配列を定義し、ファイルのすべてのバイトを一度に読み取ることができます。
短所: ファイルが大きすぎる場合、バイト配列によってメモリ オーバーフローが発生する可能性があります。
たとえば、以下に示すようなファイルを読み取ります
方法 1 :
ファイルサイズと同じ大きさのバイト配列を自分で定義し、バイト配列を読み込む方法で1回の読み込みで完了します。
public static void main(String[] args) throws Exception {
File file = new File("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
InputStream inp = new FileInputStream(file);
// 创建一个与文件大小一样的字节数组
byte[] arr = new byte[(int) file.length()];
// 读取文件, 获取读取的字节长度
int len = inp.read(arr);
System.out.println(len); // 252
// 对字节数组进行解码
String res = new String(arr);
System.out.println(res);
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
}
方法 2 :
公式は、ファイルのすべてのデータをバイト配列に直接読み取ることができる、バイト入力ストリーム InputStream 用に次の API を提供します。
メソッド名 | 例証する |
---|---|
readAllBytes() | 現在のバイト入力ストリームに対応するファイル オブジェクトのすべてのバイト データを直接読み取り、それをバイト配列にロードして返す |
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 获取文件的全部字节, 并返回一个字节数组
byte[] arr = inp.readAllBytes();
// 对字节数组进行解码
String res = new String(arr);
System.out.println(res);
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
}
ファイルバイト出力ストリーム
バイト出力ストリームを作成する
ファイル バイト出力ストリーム: クラス FileOutputStream を実装します。
機能: メモリに基づいて、メモリ内のデータがバイト形式でディスク ファイルに書き出されます。
コンストラクタは次のとおりです。
コンストラクタ | 例証する |
---|---|
FileOutputStream(ファイルファイル) | ソース ファイル オブジェクトに接続されたバイト出力ストリーム パイプを作成する |
FileOutputStream(文字列ファイルパス) | ソース ファイル パスに接続されたバイト出力ストリーム パイプを作成する |
public static void main(String[] args) throws Exception {
// 写法一: 创建输出流与源文件对象接通
OutputStream oup = new FileOutputStream(new File("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt"));
}
public static void main(String[] args) throws Exception {
// 写法二: 创建输出与源文件路径接通(常用)
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
}
ファイル出力ストリームへの書き込み
ファイルバイト出力ストリームからデータを書き込むための API :
メソッド名 | 例証する |
---|---|
書き込み (int a) | バイトを書き出す |
書き込み (byte[] バッファ) | バイト配列を書き出す |
write(byte[] buffer , int pos , int len) | バイト配列の一部を書き出します。 |
ストリームの更新と終了 API :
方法 | 例証する |
---|---|
流す() | ストリームを更新してデータの書き込みを続行する |
近い() | ストリームを閉じてリソースを解放しますが、閉じる前にストリームをフラッシュします。閉じると、データを書き込むことができなくなります |
注: データの書き込み時にはデータを更新する必要があり、使用後はストリームを閉じる必要があります。
バイトを書き出す
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
oup.write('a');
// 支持写入编码
oup.write(97);
// 汉字占三个字节, 所以该方法不可以写入汉字
// oup.write('我');
// 写数据必须刷新数据
oup.flush();
// 刷新流后可以继续写入数据
oup.write('b');
// 使用完后需要关闭流, 关闭后不能再写入数据
oup.close();
}
バイト配列を書き出す
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个字节数组
byte[] arr = {
'a', 98, 'b', 'c'};
// 写入中文, 需要将中文编码成字节数组
byte[] chinese = "中国".getBytes();
// 写入英文字节数组
oup.write(arr);
// 写入中文字节数组
oup.write(chinese);
// 关闭流(关闭之前会刷新)
oup.close();
}
バイト配列の一部を書き込む
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个字节数组
byte[] arr = {
'a', 98, 'b', 'c'};
// 写入数组的第二个和第三个元素
oup.write(arr, 1, 2);
// 关闭流(关闭之前会刷新)
oup.close();
}
補足知識:
補足1:コンテンツを書くとき、行を変更する必要がある場合は、それをバイト配列に変換して
\r\n
(ウィンドウは入力\nをサポートしますが、一部のシステムではサポートしていません。汎用性のために\r\nを使用してください)、それを書き込むことで実現できます改行の効果
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个字节数组
byte[] arr = {
'a', 98, 'b', 'c'};
oup.write(arr);
// 写入换行
oup.write("\r\n".getBytes());
// 写入数组的第二个和第三个元素
oup.write(arr, 1, 2);
// 关闭流(关闭之前会刷新)
oup.close();
}
補足 2: ファイルを書き込む場合、元のファイルが最初にクリアされ、次に新しいデータが書き込まれます 元のファイル データに基づいて新しいデータを追加する場合は、コンストラクター セットの 2 番目のパラメーターを設定する必要があります。真に
コンストラクタ | 例証する |
---|---|
FileOutputStream(ファイル file,boolean append) | ソース ファイル オブジェクトに接続されたバイト出力ストリーム パイプラインを作成し、データを追加できます |
FileOutputStream(文字列ファイルパス,boolean append) | ソース ファイル パスに接続されたバイト出力ストリーム パイプラインを作成し、データを追加できます |
public static void main(String[] args) throws Exception {
// 设置为true即可
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt", true);
}
ファイルコピーの練習
要件:
test.pdf ファイルを別のディレクトリの newtest.pdf ファイルにコピーします。
アイデア分析:
データ ソースからバイト入力ストリーム オブジェクトを作成する
宛先に基づいてバイト出力ストリーム オブジェクトを作成する
データの読み取りと書き込み、ビデオのコピー
リソースを解放する
サンプルコード:
public static void main(String[] args) {
try {
// 创建要复制文件的字节输入流
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf");
// 创建目标路径的字节输出流
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf");
// 使用文件输入流获取要复制文件的全部数据的字节数组
byte[] arr = inp.readAllBytes();
// 使用文件输出流将字节数组写入目标文件
oup.write(arr);
System.out.println("复制成功!");
// 释放资源
inp.close();
oup.close();
} catch (IOException e) {
e.printStackTrace();
}
}
質問: バイト ストリームでコピーできるファイルの種類は何ですか?
ファイルの最下層はバイトであり、コピーはバイトの単語ごとの転送であり、前後のファイルの形式とエンコードが一致している限り、問題はありません。
要約: バイト ストリームはファイルのコピーには適していますが、中国語の出力には適していません