在JAVA 中把不同的輸入輸出源(鍵盤、文件、網路連接)抽象表述爲“流”。一個流可以理解爲一個數據的序列。輸入流表示從一個源讀取數據,輸出流表示向一個目標寫數據。
Java.io 包幾乎包含了所有操作輸入、輸出需要的類。所有這些流類代表了輸入源和輸出目標。
IO流的分類
根據處理數據類型的不同分爲:字符流和字節流
* 讀寫單位不同:字節流以字節(8bit)爲單位,字符流以字符爲單位,根據碼錶映射字符,一次可能讀多個字節。
* 字節流:一次讀入或讀出是8位二進制。
* 字符流:一次讀入或讀出是16位二進制。
* 處理對象不同:設備上的數據無論是圖片或者視頻,文字,它們都以二進制存儲的。二進制的最終都是以一個8位爲數據單元進行體現,所以計算機中的最小數據單元就是字節。意味着,字節流可以處理設備上的所有數據(如圖片、avi等),而字符流只能處理字符類型的數據。只要是處理純文本數據,就優先考慮使用字符流。 除此之外都使用字節流。
根據數據流向不同分爲:輸入流和輸出流
* 輸入流只能進行讀操作,輸出流只能進行寫操作,程序中需要根據待傳輸數據的不同特性而使用不同的流。
IO流之字符流
字符流的由來: 因爲數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基於字節流讀取時,去查了指定的碼錶。(我們的系統一般都是GBK編碼)
字符流通過抽象基類Reader和Writer來操作,數據單元是16位的字符。
字符輸入流FileReader類
* 功能:讀數據一次讀取一個字符
* 構造方法:
FileReader(String fileName)
FileReader(File file)
* 常用方法
int read() 讀取單個字符,返回一個int型變量代表讀取到的字符
int read(char [] c, int offset, int len) 讀取字符到c數組,返回讀取到字符的個數
void close() 關流釋放系統底層資源
* FileReader讀取文件步驟:
A: 創建輸入流對象
B: 調用輸入流對象的讀數據方法
C: 釋放資源
* 注意事項:
用完流後記得要關閉流
使用流對象要拋出IO異常
在讀取文件時,必須保證該文件已存在,否則出異常
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Test {
public static void main(String[] args) throws IOException{
readFromFile();
}
private static void readFromFile() throws IOException {
//創建輸入流對象
Reader reader = new FileReader("D:\\TEST.txt");
//調用輸入流對象的讀數據方法
char[] buf = new char[100];
reader.read(buf);
StringBuffer s = new StringBuffer();
//如果讀取數據的返回值是-1的時候,就說明沒有數據了
while(reader.read(buf) != -1)
s.append(buf);
//釋放資源
reader.close();
System.out.println(s.toString());
}
}
字符輸入緩衝流BufferedReader類
從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取
* 緩衝區
緩衝區的出現是爲了提高流的操作效率而出現的,相對於一個字符/字節地讀取、轉換、返回來說,它有一個緩衝區,在緩衝區中封裝了一個數組,讀滿緩衝區才取出
需要被提高效率的流作爲參數傳遞給緩衝區的構造函數;一般情況下,都建議使用它們把其它Reader/InputStream包起來,使得讀取數據更高效。
* 常用方法
readline()一次讀一行,方便對文本數據的獲取。只返回回車符前面的字符,不返回回車符。如果是複製文本的話,必須加入 newLine(),寫入回車符。readLine()方法是阻塞式的, 如果到達流末尾, 就返回null。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Test {
public static void main(String[] args) throws IOException{
readFromFile();
}
private static void readFromFile() throws IOException {
Reader reader = new FileReader("D:\\TEST.txt");
BufferedReader bufr = new BufferedReader(reader);
String s = null;
while((s = bufr.readLine()) != null) {
System.out.println(s);
}
reader.close();
}
}
字符輸出流FileWriter類
* 構造方法
FileWriter(String fileName)
FileWriter(File file)
* 常用方法
void write(String str) 向文件中寫str
void flush() 將內存中的數據刷新到文件中
void close() 關流釋放系統底層資源
* FileWriter向文件中寫數據操作步驟:
A: 使用FileWriter流關聯文件
B: 利用FileWriter的寫方法寫數據
C: 利用FileWriter的刷新方法將數據從內存刷到硬盤上
D: 利用FileWriter的關流方法將釋放佔用的系統底層資源
* 注意事項:
寫入文件後必須要用flush()刷新
用完流後記得要關閉流
使用流對象要拋出IO異常
在創建一個文件時,如果目錄下有同名文件將被覆蓋
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Test {
public static void main(String[] args) throws IOException{
writeToFile();
}
private static void writeToFile() throws IOException {
File file = new File("D:\\TEST.txt");
if (!file.exists()) {
file.createNewFile();
}
//創建輸出流對象
Writer writer = new FileWriter(file, true);
//寫內容
writer.write("This\n is\n an\n example\n");
//清空緩衝區,立即將輸出流裏的內容寫到文件裏
writer.flush();
//關閉輸出流,施放資源
writer.close();
}
}
字符輸出緩衝流BufferedWriter類
將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。
* 常用方法
newLine() 寫一個換行符,這個換行符由系統決定,不同的操作系統newLine()方法使用的換行符不同(windows: \r\n|linux: \n|mac: \r)
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Test {
public static void main(String[] args) throws IOException{
writeToFile();
}
private static void writeToFile() throws IOException {
Writer writer = new FileWriter("D:\\SAMPLE.txt", true);
BufferedWriter bufw = new BufferedWriter(writer);
bufw.write("hello");
bufw.newLine();
bufw.write("Hello again");
bufw.flush();
bufw.close();
}
}
使用場景
* 文本複製
用FileReader和FileWriter實現文本複製
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
public class Test {
public static void main(String[] args) throws IOException{
copyFile();
}
private static void copyFile() throws IOException {
Reader reader = new FileReader("D:\\TEST.txt");
Writer writer = new FileWriter("D:\\copy.txt");
char[] temp = new char[1024];
while(reader.read(temp) != -1) {
writer.write(temp);
writer.flush();
}
reader.close();
writer.close();
}
}
用BufferedReader和BufferedWriter實現文本複製
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
public class Test {
public static void main(String[] args) throws IOException{
writeToFile();
}
private static void writeToFile() throws IOException {
Writer writer = new FileWriter("D:\\SAMPLE.txt", true);
BufferedWriter bufw = new BufferedWriter(writer);
Reader reader = new FileReader("D:\\TEST.txt");
BufferedReader bufr = new BufferedReader(reader);
String temp = null;
while((temp = bufr.readLine()) != null) {
bufw.write(temp);
bufw.newLine();
}
bufr.close();
bufw.flush();
bufw.close();
}
}
* 把集合中的數據寫到文本文件
把ArrayList集合中的字符串數據存儲到文本文件sample.txt中
每一個字符串元素作爲文件中的一行數據
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws IOException {
//創建集合對象
ArrayList<String> array = new ArrayList<String>();
//往集合中添加字符串元素
array.add("hello");
array.add("world");
array.add("java");
//創建輸出緩衝流對象
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\sample.txt"));
//遍歷集合,得到每一個字符串元素,然後把該字符串元素作爲數據寫到文本文件
for(String s: array) {
bw.write(s);
bw.newLine();
bw.flush();
}
//釋放資源
bw.close();
}
}
* 把文本文件中的數據讀取到集合
從sample.txt文本文件中讀取數據到ArrayList集合中,並遍歷集合,每一行數據作爲一個字符串元素
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws IOException {
//創建輸入緩衝流對象
BufferedReader br = new BufferedReader(new FileReader("D:\\sample.txt"));
//創建集合對象
ArrayList<String> array = new ArrayList<String>();
//讀取數據,每次讀取一行數據,把該行數據作爲一個元素存儲到集合中
String line;
while((line=br.readLine())!=null) {
array.add(line);
}
//釋放資源
br.close();
//遍歷集合
for(int x=0; x<array.size(); x++) {
String s = array.get(x);
System.out.println(s);
}
}
}
IO流之字節流
字節流通過抽象基類InputStream和OutputStream來操作,數據單元是8位的字節
* 字節流和字符流的基本操作是相同的,但是要想操作媒體流就需要用到字節流。
* 字節流因爲操作的是字節,所以可以用來操作媒體文件。(媒體文件也是以字節存儲的)
* 輸入字節流 InputStream
- InputStream 是所有的輸入字節流的父類,它是一個抽象類。
- ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的介質流,它們分別從Byte 數組、StringBuffer和本地文件中讀取數據。
- PipedInputStream 是從與其它線程共用的管道中讀取數據,與Piped 相關的知識後續單獨介紹。
- ObjectInputStream 和所有FilterInputStream 的子類都是裝飾流(裝飾器模式的主角)。
* 輸出字節流 OutputStream
- OutputStream 是所有的輸出字節流的父類,它是一個抽象類。
- ByteArrayOutputStream、FileOutputStream 是兩種基本的介質流,它們分別向Byte 數組和本地文件中寫入數據。
- PipedOutputStream 是向與其它線程共用的管道中寫入數據。
- ObjectOutputStream 和所有FilterOutputStream 的子類都是裝飾流。
* 字節流操作可以不用刷新流操作。
字節輸入流FileInputStream類
* 構造方法
FileInputStream(String fileName)
FileInputStream(File file)
* 常用方法
int read() 從 InputStream 對象讀取一字節的數據;該方法返回整數,若讀取的是字符串,則需強制轉換;如果已經到結尾則返回-1
int read(byte[] r) 這個方法從輸入流讀取r.length長度的字節,返回讀取的字節數。如果是文件結尾則返回-1
int available() 返回下一次對此輸入流調用方法可以不受阻塞地從此輸入流讀取的字節數。注:可以利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。但是如果文件較大,而虛擬機啓動分配的默認內存一般爲64M。當文件過大時,此數組長度所佔內存空間就會溢出。所以,此方法慎用,當文件不大時,可以使用。
void close() 關流釋放系統底層資源
字節輸入緩衝流BufferedInputStream類
BufferedInputStream比FileInputStream多了一個緩衝區,執行read時先從緩衝區讀取,當緩衝區數據讀完時再把緩衝區填滿。因此,當每次讀取的數據量很小時,FileInputStream每次都是從硬盤讀入,而BufferedInputStream大部分是從緩衝區讀入。讀取內存速度比讀取硬盤速度快得多,因此BufferedInputStream效率高。BufferedInputStream的默認緩衝區大小是8192字節。當每次讀取數據量接近或遠超這個值時,兩者效率就沒有明顯差別了。
常見應用
* 複製圖片
用FileInputStream和FileOutputStream實現圖片複製
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
FileInputStream in = new FileInputStream(new File("D:\\test.jpg"));// 指定要讀取的圖片
File file = new File("D:\\copy.jpg");
if (!file.exists()) {// 如果文件不存在,則創建該文件
file.createNewFile();
}
FileOutputStream out = new FileOutputStream(new File("D:\\copy.jpg"));// 指定要寫入的圖片
int n = 0;// 每次讀取的字節長度
byte[] bb = new byte[1024];// 存儲每次讀取的內容
while ((n = in.read(bb)) != -1) {
out.write(bb, 0, n);// 將讀取的內容,寫入到輸出流當中
}
out.close();// 關閉輸入輸出流
in.close();
}
}
用BufferedInputStream和BufferedOutputStream實現圖片複製
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
// 指定要讀取文件的緩衝輸入字節流
BufferedInputStream in = new BufferedInputStream(new FileInputStream("F:\\test.jpg"));
File file = new File("E:\\test.jpg");
if (file != null) {
file.createNewFile();
}
// 指定要寫入文件的緩衝輸出字節流
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
byte[] bb = new byte[1024];// 用來存儲每次讀取到的字節數組
int n;// 每次讀取到的字節數組的長度
while ((n = in.read(bb)) != -1) {
out.write(bb, 0, n);// 寫入到輸出流
}
out.close();// 關閉流
in.close();
}
}