第十一章【IO流】
一、流的概念
資料以二進位制的形式在程式與裝置之間流動傳輸,就像水在管道里流動一樣,所以就把這種資料傳輸的方式稱之為輸入流、輸出流。
二、流的分類
根據資料的流向分為:輸入流和輸出流
-
輸入流 :把資料從其他裝置上讀取到程式中的流
-
輸出流 :把資料從程式中寫出到其他裝置上的流
根據資料的型別分為:位元組流和字元流
-
位元組流 :以位元組為單位(byte),讀寫資料的流
-
字元流 :以字元為單位(char),讀寫資料的流
總的分類:
-
位元組輸入流,在程式中,以位元組的方式,將裝置(檔案、記憶體、網路等)中的資料讀進來
-
位元組輸出流,在程式中,以位元組的方式,將資料寫入到裝置(檔案、記憶體、網路等)中
-
字元輸入流,在程式中,以字元的方式,將裝置(檔案、記憶體、網路等)中的資料讀進來
-
字元輸出流,在程式中,以字元的方式,將資料寫入到裝置(檔案、記憶體、網路等)中
三、流的結構
幾乎所有的流,都是派生自四個抽象的父型別:
-
InputStream
,代表位元組輸入流型別 -
OutputStream
,代表位元組輸出流型別 -
Reader
,代表字元輸入流型別 -
Writer
,代表字元輸出流型別
基本流【節點流】:
位元組輸入輸出流:xxxInputStream/xxxOutputStream 【xxx:裝置】
字元輸入輸出流:xxxReader/xxxWriter
包裝流:位元組輸入輸出流,字元輸入輸出流
一般情況下,一個流,會具備最起碼的三個特點:
- 是輸入還是輸出
- 是位元組還是字元
- 流的目的地
四、位元組流
1、概述
java.io.InputStream
是所有位元組輸入流的抽象父型別
java.io.OutputStream
是所有位元組輸出流的抽象父型別
在程式碼中,使用流運算元據的的基本步驟是:
- 宣告流
- 建立流
- 使用流
- 關閉流
2、控制檯
讓程式一直讀取和寫出,那麼可以加入while迴圈,遇到“bye”結束
public class InputAndOutputStreamTest3 {
public static void main(String[] args) {
//1.宣告流
InputStream in = null;
OutputStream out = null;
//2.建立流
in = System.in;
out = System.out;
//3.使用流
int num = -1;
byte[] by = new byte[1024];
try {
while ((num = in.read(by)) != -1) {
out.write(by, 0, num);
out.flush();
if(by[num -1] == 10 && by[num -2] == 13) {
num = num - 2;
}
String str = new String(by, 0, num);
if(str.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4.關閉流
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3、位元組陣列
java.io.ByteArrayInputStream
負責從位元組陣列中讀取資料
java.io.ByteArrayOutputStream
負責把資料寫入到位元組陣列中
使用位元組流,從位元組陣列中讀取資料,以及向位元組陣列中寫資料。
public class ByteArrayStreamTest {
public static void main(String[] args) {
//1.宣告流
InputStream in = null;
OutputStream out = null;
//2.建立流
byte[] arr = "hello world".getBytes();
in = new ByteArrayInputStream(arr);
out = new ByteArrayOutputStream();
//3.使用流
int len = -1;
byte[] by = new byte[1024];
try {
len = in.read(by);
out.write(by, 0, len);
out.flush();
//4.視覺化到控制檯
String str = out.toString();
System.out.println(str);
//5.呼叫ByteArrayOutputStream中的toByteArray方法,可以將寫入到out物件中的資料返回
byte[] array = ((ByteArrayOutputStream)out).toByteArray();
System.out.println(Arrays.toString(array));
} catch (IOException e) {
e.printStackTrace();
}finally {
//6.關閉流
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4、管道
java.io.PipedInputStream
負責從管道中讀取資料
java.io.PipedOutputStream
負責將資料寫入到管道中
使用位元組流,可以從管道中讀取資料,以及向管道中寫資料。
public class PipedStreamTest {
public static void main(String[] args) {
//1.宣告流
PipedInputStream in = null;
PipedOutputStream out = null;
//2.建立流
in = new PipedInputStream();
out = new PipedOutputStream();
//3.管道對接
try {
in.connect(out);
Thread t1 = new WriterThread(out);
Thread t2 = new ReaderThread(in);
t1.start();
t2.start();
t1.join();
t2.join();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println();
System.out.println("程式執行結束");
}
}
class WriterThread extends Thread{
private OutputStream out;
public WriterThread(OutputStream out) {
this.out = out;
}
@Override
public void run() {
byte[] arr = "hello world".getBytes();
try {
for (int i = 0; i < arr.length; i++) {
out.write(arr[i]);
out.flush();
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class ReaderThread extends Thread{
private InputStream in;
public ReaderThread(InputStream in) {
this.in = in;
}
@Override
public void run() {
int len = -1;
try {
while ((len = in.read()) != -1) {
System.out.write(len);
System.out.flush();
}
System.out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5、檔案
java.io.File
類,是java中對檔案和目錄的抽象表示,主要用於檔案和目錄的建立、查詢和刪除等操作。
常用方法:
public String getAbsolutePath()
,返回file的絕對路徑
public String getPath()
,返回建立file物件時傳入的路徑引數(有可能是相對路徑)
public String getName()
,返回file的名字
public long length()
,file如果表示檔案,則返回檔案內容的長度(位元組個數)
public boolean exists()
,判斷此檔案或目錄是否真的存在
public boolean isDirectory()
,判斷File表示的是否是一個目錄
public boolean isFile()
,判斷file表示的是否是一個檔案
使用位元組流,可以從檔案中讀取資料,以及向檔案中寫資料。
java.io.FileInputStream
,負責從檔案中讀取資料
java.io.FileOutputStream
,負責把資料寫入到檔案中
public class FileStreamTest {
public static void main(String[] args) {
//1.宣告流
InputStream in = null;
OutputStream out = null;
//2.建立流
try {
File f1 = new File("src/com/sxu/day19/test/a.txt");
File f2 = new File("src/com/sxu/day19/test/b.txt");
in = new FileInputStream(f1);
out = new FileOutputStream(f2);
//3.使用流
int len = -1;
byte[] by = new byte[1024];
while ((len = in.read(by)) != -1) {
out.write(by,0,len);
}
out.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6、網路
轉至 12.網路程式設計.md
五、字元流
1、概述
字元流,可以用字元的形式,讀寫資料,專門用於處理文字資料。
java.io.Reader
是所有字元輸入流的抽象父型別
java.io.Writer
是所有字元輸出流的抽象父型別
2、字元陣列
使用字元流,從字元陣列中讀取資料,以及向字元陣列中寫資料。
java.io.CharArrayReader
負責從字元陣列中讀取資料
java.io.CharArrayWriter
負責把資料寫入到字元陣列中
public class ReaderAndWriterStreamTest {
public static void main(String[] args) {
//1.宣告流
Reader in = null;
Writer out = null;
//2.建立流
char[] arr = "hello world".toCharArray();
in = new CharArrayReader(arr);
out = new CharArrayWriter();
//3.使用流
int len = -1;
char[] ch = new char[1024];
try {
len = in.read(ch);
out.write(ch, 0, len);
out.flush();
String str = out.toString();
System.out.println(str);
//CharArrayWriter中的toCharArray方法,可以將寫入到out物件中的資料返回
char[] charArray = ((CharArrayWriter)out).toCharArray();
System.out.println(Arrays.toString(charArray));
} catch (IOException e) {
e.printStackTrace();
}finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3、管道
使用字元流,可以從管道中讀取資料,以及向管道中寫資料。
java.io.PipedReader
負責從管道中讀取資料
java.io.PipedWriter
負責將資料寫入到管道中
public class PipedTest {
public static void main(String[] args) {
PipedReader in = null;
PipedWriter out = null;
in = new PipedReader();
out = new PipedWriter();
try {
in.connect(out);
Thread t1 = new WriterThreaed(out);
Thread t2 = new ReaderThread(in);
t1.start();
t2.start();
t1.join();
t2.join();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println();
System.out.println("程式執行結束");
}
}
class WriterThreaed extends Thread{
private Writer out;
public WriterThreaed(Writer out) {
this.out = out;
}
@Override
public void run() {
char[] arr = "hello world".toCharArray();
try {
for (int i = 0; i < arr.length; i++) {
out.write(arr[i]);
out.flush();
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class ReaderThread extends Thread{
private Reader in;
public ReaderThread(Reader in) {
this.in = in;
}
@Override
public void run() {
int len = -1;
try {
while ((len = in.read()) != -1) {
System.out.write(len);
System.out.flush();
}
System.out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4、檔案
使用字元流,可以從檔案中讀取資料,以及向檔案中寫資料。
java.io.FileReader
,負責從檔案中讀取資料
java.io.FileWriter
,負責把資料寫入到檔案中
public class FileTest {
public static void main(String[] args) {
//1.宣告流
Reader in = null;
Writer out = null;
try {
//2.建立流
File f1 = new File("src/com/sxu/day20/test/a.txt");
File f2 = new File("src/com/sxu/day20/test/b.txt");
in = new FileReader(f1);
out = new FileWriter(f2);
//3.使用流
int len = -1;
char[] ch = new char[1024];
while ((len = in.read(ch)) != -1) {
out.write(ch,0,len);
}
out.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5、其他
其他情況,使用字元流進行讀寫資料時,可以藉助於位元組流,將位元組流轉換為字元流來操作。因為字元流底層也是以位元組為單位來運算元據的,只不過中間會把位元組按照預設或指定的字元編號,把位元組轉成了字元而已。
六、節點流
位元組流和字元流,都屬於節點流
它們的特點是,可以【直接】讀取某一個地方的資料,或者【直接】把資料寫入到某一個地方。
七、資料流
DataOutputStream
負責把指定型別的資料,轉化為位元組並寫出去
DataInputStream
負責把讀取到的若干個位元組,轉化為指定型別的資料
八、緩衝流
位元組緩衝流
java.io.BufferedInputStream
,負責給位元組輸入流提供緩衝功能
java.io.BufferedOutputStream
,負責給位元組輸出流提供緩衝功能
字元緩衝流
java.io.BufferedReader
,負責給字元輸入流提供緩衝功能
java.io.BufferedWriter
,負責給字元輸出流提供緩衝功能
九、轉換流
java.io.OutputStreamWriter
,可以將位元組輸出流轉換為字元輸出流,並指定編碼
java.io.InputStreamReader
,可以將位元組輸入流轉換為字元輸入流,並指定編碼
十、物件流
在java中,並非所有物件都可以進行序列化和反序列化,而是隻有實現了指定介面的物件才可以進行。java.io.Serializable
介面
java.io.ObjectOutputStream
,將Java物件轉換為位元組序列,並輸出到記憶體、檔案、網路等地方java.io.ObjectInputStream
,從某一個地方讀取出物件的位元組序列,並生成對應的物件
java中的關鍵字transient
,可以修飾類中的屬性,它的讓物件在進行序列化的時候,忽略掉這個被修飾的屬性
十一、隨機訪問流
java.io.RandomAccessFile
是JavaAPI中提供的對檔案進行隨機訪問的流