流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱爲流,流的本質是數據傳輸,根據數據傳輸特性將流抽象爲各類類,方便更直觀的進行數據操做。流的源端和目的端可簡單地當作是數據的生產者和消費者,對輸入流,可沒必要關心它的源端是什麼,只要簡單地從流中讀數據,而對輸出流,也可不知道它的目的端,只是簡單地往流中寫數據。java
按照流向劃分數據流可分爲輸入流和輸出流。數組
輸入流:從磁盤,光盤,網絡,鍵盤輸入數據到內存。io包中的輸入流都繼承自InputStream或Reader。緩存
輸出流:從內存輸出數據到磁盤,磁帶,顯示器等地。io包中的輸出流都繼承自OutputStream或Writer。網絡
按照數據組織形式劃分數據流可分爲字節流和字符流。多線程
字節流:byte爲數據的最小單位。io包中的輸入流都繼承自InputStream或OutputStream。app
字符流:char爲數據的最小單位。io包中的輸入流都繼承自Reader或Writer。測試
按照功能劃分數據流可分爲低級流(節點流)和高級流(處理流)。this
低級流(節點流):節點流是能夠直接從/向一個特定的數據源(例如磁盤、內存、網絡)讀/寫數據的流。編碼
高級流(處理流):高級流不可直接從數據源讀/寫數據,而是鏈接在已存在的流(能夠是低級流或高級流)之上,爲流添加額外的擴展功能。spa
輸入輸出流整體劃分
字節流分類及其做用
字符流分類及其做用
public abstract void write(int b) //向輸出流寫入單個字節
public void write(byte[] data) //將字節數組data中數據寫入到輸出流中
public void write(byte[] data, int offset, int length) //將字節數組data中「offset開始,共length長「的數據寫入到輸出流中
public void flush() //刷新該輸出流,強制數據寫入到輸出流
void close() //關閉輸出流並釋放與該流關聯的全部系統資源
int available() //能夠不受阻塞地今後輸入流讀取(或跳過)的估計字節數
void close() //關閉此輸入流並釋放與該流關聯的全部系統資源
void mark(int readlimit) //在此輸入流中標記當前的位置,若是讀取字節數超過readlimit,則不標記任何字節
boolean markSupported() //測試此輸入流是否支持 mark 和 reset 方法
abstract int read() //從輸入流中讀取數據的下一個字節
int read(byte[] b) //從輸入流中讀取必定數量的字節,並將其存儲在字節數組 b 中
int read(byte[] b, int off, int len) //將輸入流中從"off開始的最多 len字節數據"讀入 byte 數組
void reset() //將此流從新定位到最後一次對此輸入流調用 mark 方法時的位置
long skip(long n) //跳過和丟棄此輸入流中數據的 n 個字節
abstract void close() //關閉該流並釋放與之關聯的全部資源
void mark(int readAheadLimit) //標記流中的當前位置
boolean markSupported() //判斷此流是否支持 mark() 操做
int read() //讀取單個字符
int read(char[] cbuf) //將字符讀入數組
abstract int read(char[] cbuf, int off, int len) //將字符讀入數組的「offset開始,共length長」的部分
int read(CharBuffer target) //試圖將字符讀入指定的字符緩衝區
boolean ready() //判斷是否準備讀取此流
void reset() //將此流從新定位到最後一次對此輸入流調用 mark 方法時的位置
long skip(long n) //跳過個字符
Writer append(char c) //將單個字符添加到輸出流 追加模式
Writer append(CharSequence csq) //將指定字符序列添加到輸出
Writer append(CharSequence csq, int start, int end) //將指定字符序列的子序列添加到輸出流
abstract void close() //關閉此流
abstract void flush() //刷新該流的緩衝
void write(char[] cbuf) //寫入字符數組
abstract void write(char[] cbuf, int off, int len) //寫入字符數組的某一部分
void write(int c) //寫入單個字符
void write(String str) //寫入字符串
void write(String str, int off, int len) //寫入字符串的某一部分
ByteArrayOutputStream:寫入ByteArrayOutputStream的數據被寫入到一個byte數組,緩衝區會隨着數據的不斷寫入而自動增加;可以使用toByteArray()和toString()獲取數據;沒法關閉,調用close方法仍然能夠以後向該流寫入數據。(ByteArrayInputStream相似)
public static void main(String args[]) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(1); //緩衝區長度爲4 baos.write("helloworld".getBytes()); //可寫入超過1字節數據 byte b[] = baos.toByteArray(); String str = baos.toString(); //toByteArray和toString方法 baos.close(); //嘗試關閉 baos.write("!".getBytes()); //仍可寫入 baos.writeTo(System.out); //寫到特定輸出流中 //結果:helloworld! }
FileoutputStream:用於向文件進行寫入操做,getFD方法可獲取文件描述符,getChannel方法可獲取文件通道。
FileOutputStream fos = new FileOutputStream("fa.txt"); FileChannel fc = fos.getChannel(); FileDescriptor fd = fos.getFD();
ObjectOutputStream:組合ObjectInputStream來進行對基本數據或者對象的持久存儲。
PipedOutputStream:和PipedInputStream一塊兒使用,能實現多線程間的管道通訊。
DataOutputStream:裝飾其餘的輸出流,容許應用程序以與機器無關方式向底層寫入基本Java數據類型。(DataInputStream相似效果)
DataOutputStream dos = new DataOutputStream(new ByteArrayOutputStream()); dos.writeDouble(3.14); //寫入double類型 dos.writeBoolean(true); //寫入布爾類型 dos.writeChar(97); //寫入char類型
BufferedOutputStream:爲另外一個輸出流添加緩衝功能,BufferedInputStream相似效果。
PrintStream:裝飾其餘輸出流,爲其餘輸出流添加功能,方便的打印各類數據值。
ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); ps.format("%-3.2f",3.1415926); baos.writeTo(System.out); //結果:3.14
PushbackInputStream:容許從流中讀取數據,而後在須要時推回該流。
byte[] b = "heo".getBytes(); PushbackInputStream pis = new PushbackInputStream(newByteArrayInputStream(b),3); //回推緩存三字節 byte[] bb = new byte[5]; pis.read(bb,0,2); //將b中數據he讀入輸入流中 pis.unread("ll".getBytes()); //將ll放入回推緩存 pis.read(bb,2,3); //讀取回推緩存數據後再讀取b中數據 System.out.println(new String(bb)); //結果 //hello
OutputStreamWriter:從字符流到字節流的橋接,自動將要寫入流中的字符編碼成字節。
ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(baos,"utf-8"); //指定編碼 osw.write("Sakura\n"); osw.write("最好了"); osw.flush(); baos.writeTo(System.out); //結果 //Sakura //最好了
一,數據輸入仍是輸出
1) 輸入:使用Reader、InputStream 類型的子類。
2) 輸出:使用Writer、OutputStream 類型的子類。
二,數據格式
1) 二進制格式:使用InputStream、OutputStream 及其全部帶 Stream結尾的子類。
2) 純文本格式:使用Reader、Writer 及其全部帶 Reader、Writer 的子類。
三,數據源
1) 文件:字節流使用FileInputStream和FileOutputStream;對於字符流使用FileReader和 FileWriter。
2) 字節數組:則使用ByteArrayInputStream和ByteArrayOutputStream。
3) 字符數組:則使用CharArrayReader和CharArrayWriter。
4) String對象:字節流使用StringBufferInputStream和StringBufferOuputStream;字符流使用StringReader和StringWriter。
6、特殊須要
1) 轉換流:InputStreamReader、OutputStreamWriter。
2) 對象輸入輸出:ObjectInputStream、ObjectOutputStream。
3) 線程間通訊:PipeInputStream、PipeOutputStream、PipeReader、PipeWriter。
4) 合併輸入:SequenceInputStream。
5) 格式化輸出,則使用PrintStream或PrintWriter。
6)更特殊的須要:PushbackInputStream、PushbackReader、LineNumberInputStream、LineNumberReader。
7、緩衝
字節流使用BufferedInputStream和BufferedOutputStream;字節流使用BufferedReader和BufferedWriter。
複製文件夾的類
import java.io.*; public class Test{ public static void main(String[] args) { copyClass cc = new copyClass("src\\old","src\\new"); try { long start = System.currentTimeMillis(); cc.copyDir(cc.getSource(),cc.getDestination(),false); long end = System.currentTimeMillis(); System.out.println(end-start); }catch (IOException e){ e.printStackTrace(); } } } class copyClass{ private File source; private File destination; copyClass(String source, String destination){ this.source = new File(source); this.destination = new File(destination); } void copyContent(File source,File destination,boolean byByte) throws IOException { if(byByte){ //字節數組複製 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destination)); byte[] b = new byte[1024]; while (bis.available()!= 0){ bis.read(b); bos.write(b); bos.flush(); } bis.close(); bos.close(); } else { //單個字節複製 FileInputStream fis = new FileInputStream(source); FileOutputStream fos = new FileOutputStream(destination); while (fis.available()!=0){ int i = fis.read(); fos.write(i); } fis.close(); fos.close(); } } void copyDir(File source, File destination,boolean byBytes) throws IOException{ if (!source.isDirectory()){ //是文件則複製其內容 copyContent(source,destination,byBytes); } else { if (destination.mkdirs()){ //是文件夾則遞歸複製 File[] fs = source.listFiles(); for (int i = 0; i < fs.length; i++) { String fileName = fs[i].getName(); File newDestination = new File(destination.getPath() + File.separator + fileName); copyDir(fs[i], newDestination,byBytes); } } else { System.out.print("Creat dirs failed!"); } } } public File getSource() { return source; } public void setSource(File source) { this.source = source; } public File getDestination() { return destination; } public void setDestination(File destination) { this.destination = destination; } }
結果
//採用單個字節複製方法耗時 1317 //採用緩衝區字節數組複製方法耗時 52 //減小了超過95%的時間
相當重要的是:除非數據流很是小,不然都應該使用數組來進行流的處理,必要時可用BufferedInputStream或BufferedOutputStream或BufferedWriter/BufferedReader來進行緩衝處理。