流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱為流,流的本質是數據傳輸,根據數據傳輸特性將流抽象為各種類,方便更直觀的進行數據操作。
根據處理數據類型的不同分為:字符流和字節流根據數據流向不同分為:輸入流和輸出流字符流的由來: 因為數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基於字節流讀取時,去查了指定的碼表。字節流和字符流的區別:
(1)讀寫單位不同:字節流以字節(8bit)為單位,字符流以字符為單位,根據碼表映射字符,一次可能讀多個字節。
(2)處理對象不同:字節流能處理所有類型的數據(如圖片、avi等),而字符流只能處理字符類型的數據。
(3)字節流在操作的時候本身是不會用到緩沖區的,是文件本身的直接操作的;而字符流在操作的時候下後是會用到緩沖區的,是通過緩沖區來操作文件,我們將在下面驗證這一點。
優先選用字節流。首先因為硬盤上的所有文件都是以字節的形式進行傳輸或者保存的,包括圖片等內容。但是字符只是在內存中才會形成的,所以在開發中,字節流使用廣泛。
字符流類圖示:

字節流類圖示:

用來讀取字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩沖區大小都是適當的。要自己指定這些值,可以先在 FileInputStream 上構造一個 InputStreamReader。
FileReader 用於讀取字符流。要讀取原始字節流,可以考慮使用 FileInputStream。
/**
* 此讀入方式由於一次讀一個字符,所以效率很低
* 使用字符流讀取一個文本文件,將讀取到的文本內容打印到控制台。
*/
public class Test {
public static void main(String[] args) {
FileReader fr = null;
try {
//指定讀入流
fr = new FileReader("abc.txt");
int ch = 0;
//判斷是否讀取到文件末尾
while ((ch = fr.read()) != -1) {
System.out.println(ch);
}
}
//捕獲異常
catch (IOException e) {
throw new RuntimeException("讀取失敗");
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
System.err.println("關閉失敗");
}
}
}
}
}
/**
* 此讀入方式由於每次讀入一塊而非單個字符,所以效率高
* 使用字符流讀取一個文本文件,將讀取到的文本內容打印到控制台。
*/
public class Test {
public static void main(String[] args) {
FileReader fr = null;
try {
//指定讀入流
fr = new FileReader("abc.txt");
//指定一個緩沖區
char[] buf = new char[1024];
int len =0;
//判斷是否讀取到文件末尾
while ((len = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
}
//捕獲異常
catch (IOException e) {
throw new RuntimeException("讀取失敗");
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
System.err.println("關閉失敗");
}
}
}
}
}
用來寫入字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩沖區大小都是可接受的。要自己指定這些值,可以先在 FileOutputStream 上構造一個 OutputStreamWriter。
文件是否可用或是否可以被創建取決於底層平台。特別是某些平台一次只允許一個 FileWriter(或其他文件寫入對象)打開文件進行寫入。在這種情況下,如果所涉及的文件已經打開,則此類中的構造方法將失敗。
FileWriter 用於寫入字符流。要寫入原始字節流,可以考慮使用 FileOutputStream。
/**
* 在磁盤上寫一個文件,並且向文件中寫入相應的字母。
* 對IO操作實現異常處理
*/
public class Test {
public static void main(String[] args) {
// 指定一個輸出源
FileWriter fw = null;
try {
fw = new FileWriter("d:\\abc.txt");
// 寫入數據
fw.write("abcd");
} catch (IOException e) {
// e.printStackTrace();
throw new RuntimeException("寫入失敗");
} finally {
// 刷新並關閉資源
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("關閉失敗");
}
}
}
}
}
字符流復制一個文本文件,單個字節寫入:
/**
* 字符流復制一個文本文件
*/
public class Test {
public static void main(String[] args) {
// 有一個讀取源和寫入源
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("d:\\abc.txt");
fw = new FileWriter("d:\\abc_copy.txt");
// 不斷讀取並且寫
int ch = 0;
while ((ch = fr.read()) != -1) {
fw.write(ch);
}
} catch (Exception e) {
throw new RuntimeException("復制失敗");
} finally {
// 關閉流
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
System.out.println("關閉失敗");
}
}
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
System.out.println("關閉失敗");
}
}
}
}
}
文件復制(FileWriter和FileReader結合,字節數組緩沖方法讀寫):
/**
* 字符流復制一個文本文件(高效方法、異常處理)。
*/
public class Test {
public static void main(String[] args) {
// 讀取源和寫入源
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("d:\\abc.txt");
fw = new FileWriter("d:\\abc_copy.txt");
// 利用自定義的緩存數組高效讀寫
char[] buf = new char[1024];
int len = 0;
//判斷是否讀到文件末尾,若沒有,則繼續
while ((len = fr.read(buf)) != -1) {
//一次寫入一個緩沖塊
fw.write(buf, 0, len);
}
} catch (Exception e) {
throw new RuntimeException("復制失敗");
} finally {
// 判斷讀入流對象是否還存在,若存在則關閉
if (fr != null) {
try {
//關閉讀入流
fr.close();
} catch (IOException e) {
System.out.println("關閉失敗");
}
}
//判斷寫出流對象是否還存在,若存在則關閉
if (fw != null) {
try {
//關閉寫出流
fw.close();
} catch (IOException e) {
System.out.println("關閉失敗");
}
}
}
}
}
從字符輸入流中讀取文本,緩沖各個字符,從而實現字符、數組和行的高效讀取。
可以指定緩沖區的大小,或者可使用默認的大小。大多數情況下,默認值就足夠大了。
通常,Reader 所作的每個讀取請求都會導致對底層字符或字節流進行相應的讀取請求。因此,建議用 BufferedReader 包裝所有其 read() 操作可能開銷很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in = new BufferedReader(new FileReader("foo.in"));
將緩沖指定文件的輸入。如果沒有緩沖,則每次調用 read() 或 readLine() 都會導致從文件中讀取字節,並將其轉換為字符後返回,而這是極其低效的。
通過用合適的 BufferedReader 替代每個 DataInputStream,可以對將 DataInputStream 用於文字輸入的程序進行本地化。
/**
* 高效讀取文本數據
*/
public class Test {
public static void main(String[] args) throws IOException {
FileReader fr = null;
BufferedReader bfr = null;
try {
//獲取讀入源
fr = new FileReader("abc.txt");
bfr = new BufferedReader(fr);
String line = null;
//循環將數據讀入字符數組
while ((line = bfr.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
throw new RuntimeException("讀取文件失敗");
} finally {
if (bfr != null) {
try {
//關閉流
bfr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
將文本寫入字符輸出流,緩沖各個字符,從而提供單個字符、數組和字符串的高效寫入。
可以指定緩沖區的大小,或者接受默認的大小。在大多數情況下,默認值就足夠大了。
該類提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系統屬性 line.separator 定義。並非所有平台都使用新行符 ('\n') 來終止各行。因此調用此方法來終止每個輸出行要優於直接寫入新行符。
通常 Writer 將其輸出立即發送到底層字符或字節流。除非要求提示輸出,否則建議用 BufferedWriter 包裝所有其 write() 操作可能開銷很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
將緩沖 PrintWriter 對文件的輸出。如果沒有緩沖,則每次調用 print() 方法會導致將字符轉換為字節,然後立即寫入到文件,而這是極其低效的。
/**
* 字符流 copy文本文件
*/
public class Test {
private static int BUFFER_SIZE = 1024;
public static void main(String[] args) throws IOException {
copy_text();
}
/*
* 指定一個讀取源 讀取源是文本文件
* 指定一個寫入目的 也是一個文件 文件名可以和源讀取文件不一樣
* 頻繁讀取文本文件的內容 頻繁的寫入緩沖區
* 關閉並且刷新內容到目的地
*/
public static void copy_text() {
FileReader fr = null;
FileWriter fw = null;
BufferedReader bfr = null;
BufferedWriter bfw = null;
//定義源
try {
//讀取源
fr = new FileReader("d:\\abc.txt");
//高效讀取
bfr = new BufferedReader(fr);
//寫入源
fw = new FileWriter("d:\\cc.txt");
//高效寫入
bfw = new BufferedWriter(fw);
//循環讀寫文件至末尾
String line = null;
while ((line = bfr.readLine()) != null) {
bfw.write(line);
bfw.newLine();
bfw.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
//關閉流
if (bfr != null) {
try {
bfr.close();
} catch (IOException e) {
throw new RuntimeException("關閉失敗");
}
}
if (bfw != null) {
try {
bfw.close();
} catch (IOException e) {
throw new RuntimeException("關閉失敗");
}
}
}
}
}
FileInputStream 從文件系統中的某個文件中獲得輸入字節。
FileInputStream 用於讀取諸如圖像數據之類的原始字節流。要讀取字符流,可以考慮使用 FileReader。
逐個字節讀取文本文件:
/**
* 字節流
* 讀文件內容,節省空間
*/
public class Test {
public static void main(String[] args) throws IOException {
//創建文件讀取的文件對象
String fileName = "abc.txt";
File f = new File(fileName);
//獲取讀入流
InputStream in = new FileInputStream(f);
//獲取文件字節大小,然後創建字節數組 (不適合過大文件的讀取)
byte[] b = new byte[(int) f.length()];
//循環讀取字節
for (int i = 0; i < b.length; i++) {
b[i] = (byte) in.read();
}
if(in != null){
try {
//關閉讀取流對象
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(new String(b));
}
}
通過字節流數組緩沖,高效讀取文本文件:
/**
* 字節流
* 讀文件內容,節省空間
*/
public class Test {
public static void main(String[] args) throws IOException {
//創建文件讀取的文件對象
String fileName = "abc.txt";
File f = new File(fileName);
//獲取讀入流
InputStream in = new FileInputStream(f);
//獲取文件字節大小,然後創建字節數組 (不適合過大文件的讀取)
byte[] buf = new byte[1024];
//循環讀取字節
int len = 0;
//創建StringBuilder對象,用於連接讀取後字符形成的字符串
StringBuilder sb = new StringBuilder();
while ((len = in.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
if (in != null) {
try {
//關閉讀取流對象
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(sb.toString());
}
}
文件輸出流是用於將數據寫入 File 或 FileDescriptor 的輸出流。文件是否可用或能否可以被創建取決於基礎平台。特別是某些平台一次只允許一個 FileOutputStream(或其他文件寫入對象)打開文件進行寫入。在這種情況下,如果所涉及的文件已經打開,則此類中的構造方法將失敗。
FileOutputStream 用於寫入諸如圖像數據之類的原始字節的流。要寫入字符流,可以考慮使用 FileWriter。
逐個字節寫出到文件:
public class Test {
public static void main(String[] args) throws IOException {
//定義寫出的文件對象
String fileName ="hello.txt";
File f = new File(fileName);
//獲取寫出流對象
OutputStream out = new FileOutputStream(f);
//OutputStream out = new FileOutputStream(f,true); //以追加方式寫入文件
String str = "Hello World!!";
//把字符串轉成字節數組
byte[] b = str.getBytes();
//逐個字節寫出到文件
for (int i = 0; i < b.length; i++) {
out.write(b[i]);
}
//關閉寫出流對象
out.close();
}
}
通過字節數組寫入到文件:
/**
* 字節流
* */
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
//定義寫出的文件對象
String fileName ="hello.txt";
File f = new File(fileName);
//獲取寫出流對象
OutputStream out = new FileOutputStream(f);
//OutputStream out = new FileOutputStream(f,true); //以追加方式寫入文件
String str = "Hello World!!";
//把字符串轉成字節數組
byte[] bytes = str.getBytes();
//通過寫出流寫出到文件
out.write(bytes);
//關閉寫出流對象
out.close();
}
}
BufferedInputStream:
BufferedInputStream 為另一個輸入流添加一些功能,即緩沖輸入以及支持 mark 和 reset 方法的能力。在創建 BufferedInputStream 時,會創建一個內部緩沖區數組。在讀取或跳過流中的字節時,可根據需要從包含的輸入流再次填充該內部緩沖區,一次填充多個字節。mark 操作記錄輸入流中的某個點,reset 操作使得在從包含的輸入流中獲取新字節之前,再次讀取自最後一次 mark 操作後讀取的所有字節。
該類實現緩沖的輸出流。通過設置這種輸出流,應用程序就可以將各個字節寫入底層輸出流中,而不必針對每次字節寫入調用底層系統。
/*
* 復制圖片
*/
public class Test {
public static void copy_jpg() throws IOException {
//定義圖片讀取源
FileInputStream fis = new FileInputStream("d:\\");
BufferedInputStream bfis = new BufferedInputStream(fis);
//定義圖片寫入源
FileOutputStream fos = new FileOutputStream("d:\\1.mkv");
BufferedOutputStream bfos = new BufferedOutputStream(fos);
//使用字節緩沖數組,高效讀取
byte[] buf = new byte[1024];
int len = 0;
while ((len = bfis.read(buf)) != -1) {
bfos.write(buf, 0, len);
//不需要這個刷新,查API文檔可知這個flush方法中無有效執行代碼
//bfos.flush();
}
//關閉讀入流
bfis.close();
//關閉寫出流
bfos.close();
}
}
InputStreamReader 是字節流通向字符流的橋梁:它使用指定的 charset讀取字節並將其解碼為字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平台默認的字符集。
每次調用 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個字節。要啟用從字節到字符的有效轉換,可以提前從底層流讀取更多的字節,使其超過滿足當前讀取操作所需的字節。
為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
/**
* 將字節流轉換為字符流
*/
public class Test {
public static void main(String[] args) throws IOException {
//控制台輸入
InputStream in = System.in;
//將字節流轉化為字符流
InputStreamReader isr = new InputStreamReader(in);
int ch = 0;
//循環讀取
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
isr.close();
}
}
字符編碼:
/**
* 讀取window創建的文件--其中有中文字符
*/
public class Test {
public static void main(String[] args) throws IOException {
//使用字節流讀取一個指定的文本文件
FileInputStream fis = new FileInputStream("d:\\b.txt");
//使用轉換流將文本文件內容轉換為字符流 轉換時指定對應的字符集進行讀取
InputStreamReader isr = new InputStreamReader(fis, "gbk");
//高效讀取
BufferedReader bfr = new BufferedReader(isr);
int ch = 0;
//循環讀取
while ((ch = isr.read()) != -1) {
System.out.println((char) ch);
}
}
}
/**
* 復制一個文本文件(指定讀入寫出編碼)
*/
public class Test {
public static void main(String[] args) throws IOException {
//讀取源文件
//轉換並指定編碼進行讀取
//高效讀取
BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream("d:\\abc.txt"), "gbk"));
//目標文件
//指定編碼集進行寫入
//高效寫入
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:\\ccc.txt"), "gbk"));
//循環讀取並且寫入目標文件
String line = null;
while((line = bfr.readLine()) != null){
bfw.write(line);
//寫入換行符(由於bfw整行讀取,不包括換行符,所以需要自己添加)
bfw.newLine();
//刷新緩沖區
bfw.flush();
}
//關閉流
bfr.close();
bfw.close();
}
}
數據輸入流允許應用程序以與機器無關方式從底層輸入流中讀取基本 Java 數據類型。應用程序可以使用數據輸出流寫入稍後由數據輸入流讀取的數據。
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("d:" + File.separator + "hello.txt");
//創建讀入流對象input
DataInputStream input = new DataInputStream(new FileInputStream(file));
char[] ch = new char[10];
int count = 0;
char temp;
//循環讀取
while ((temp = input.readChar()) != 'C') {
ch[count++] = temp;
}
System.out.println(ch);
}
}
數據輸出流允許應用程序以適當方式將基本 Java 數據類型寫入輸出流中。然後,應用程序可以使用數據輸入流將數據讀入。
public class Test {
public static void main(String[] args) throws IOException {
//創建文件對象
File file = new File("d:" + File.separator + "hello.txt");
char[] ch = {'A', 'B', 'C'};
DataOutputStream out = null;
//創建讀入流對象
out = new DataOutputStream(new FileOutputStream(file));
for (char temp : ch) {
//寫入字符
out.writeChar(temp);
}
out.close();
}
}
PushbackInputStream 為另一個輸入流添加性能,即“推回 (push back)”或“取消讀取 (unread)”一個字節的能力。在代碼片段可以很方便地讀取由特定字節值分隔的不定數量的數據字節時,這很有用;在讀取終止字節後,代碼片段可以“取消讀取”該字節,這樣,輸入流上的下一個讀取操作將會重新讀取被推回的字節。例如,表示構成標識符字符的字節可能由表示操作符字符的字節終止;用於讀取一個標識符的方法可以讀取到遇到操作符為止,然後將該操作符推回以進行重讀。
public class Test {
public static void main(String[] args) throws IOException {
String str = "hello,rollenholt";
PushbackInputStream push = null;
ByteArrayInputStream bat = null;
//創建ByteArrayInputStream讀入流對象
bat = new ByteArrayInputStream(str.getBytes());
//創建PushbackInputStream讀入流對象
push = new PushbackInputStream(bat);
int temp = 0;
while ((temp = push.read()) != -1) {
if (temp == ',') {
//推回 byte 數組的某一部分:將其復制到推回緩沖區之前。
push.unread(temp);
//從此輸入流中讀取下一個數據字節
temp = push.read();
System.out.print("(回退" + (char) temp + ") ");
} else {
System.out.print((char) temp);
}
}
}
}
管道輸入流應該連接到管道輸出流;管道輸入流提供要寫入管道輸出流的所有數據字節。通常,數據由某個線程從 PipedInputStream 對象讀取,並由其他線程將其寫入到相應的 PipedOutputStream。不建議對這兩個對象嘗試使用單個線程,因為這樣可能死鎖線程。管道輸入流包含一個緩沖區,可在緩沖區限定的范圍內將讀操作和寫操作分離開。如果向連接管道輸出流提供數據字節的線程不再存在,則認為該管道已損壞。
可以將管道輸出流連接到管道輸入流來創建通信管道。管道輸出流是管道的發送端。通常,數據由某個線程寫入 PipedOutputStream 對象,並由其他線程從連接的 PipedInputStream 讀取。不建議對這兩個對象嘗試使用單個線程,因為這樣可能會造成該線程死鎖。如果某個線程正從連接的管道輸入流中讀取數據字節,但該線程不再處於活動狀態,則該管道被視為處於 毀壞 狀態。
/**
* 管道流
*/
class Test {
public static void main(String[] args) throws IOException {
//創建發送對象
Send send = new Send();
//創建接收對象
Recive recive = new Recive();
try {
//管道連接
send.getOut().connect(recive.getInput());
} catch (Exception e) {
e.printStackTrace();
}
new Thread(send).start();
new Thread(recive).start();
}
}
/**
* 消息發送類
*/
class Send implements Runnable {
private PipedOutputStream out = null;
//無參構造函數
public Send() {
out = new PipedOutputStream();
}
//獲取管道寫出流
public PipedOutputStream getOut() {
return this.out;
}
@Override
//重寫Runnable接口的run()方法
public void run() {
String message = "hello , Alice";
try {
out.write(message.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
try {
//關閉寫出流
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 接受消息類
*/
class Recive implements Runnable {
private PipedInputStream input = null;
//無參構造函數
public Recive() {
this.input = new PipedInputStream();
}
//獲取管道讀入流對象
public PipedInputStream getInput() {
return this.input;
}
@Override
//重寫Runnable接口的run()方法
public void run() {
byte[] b = new byte[1000];
int len = 0;
try {
len = this.input.read(b);
} catch (Exception e) {
e.printStackTrace();
}
try {
//關閉讀入流對象
input.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("接受的內容: " + (new String(b, 0, len)));
}
}
此類為以 ZIP 文件格式寫入文件實現輸出流過濾器。包括對已壓縮和未壓縮條目的支持。
/**
* 創建壓縮文件示例
*/
public class Test {
public static void main(String[] args) throws IOException {
//創建壓縮源文件對象
File file = new File("d:" + File.separator + "hello.txt");
//創建壓縮文件對象
File zipFile = new File("d:" + File.separator + "hello.zip");
//創建源文件讀入流對象
InputStream input = new FileInputStream(file);
//創建壓縮文件寫出流對象
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(
zipFile));
//開始寫入新的 ZIP 文件條目並將流定位到條目數據的開始處
zipOut.putNextEntry(new ZipEntry(file.getName()));
// 設置注釋
zipOut.setComment("hello");
int temp = 0;
//循環寫入字節
while ((temp = input.read()) != -1) {
zipOut.write(temp);
}
//關閉讀入流
input.close();
//關閉寫出流
zipOut.close();
}
}
ZipOutputStream類壓縮多個文件:
public class Test {
public static void main(String[] args) throws IOException {
// 要被壓縮的文件夾
File file = new File("d:" + File.separator + "temp");
File zipFile = new File("d:" + File.separator + "zipFile.zip");
InputStream input = null;
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(
zipFile));
zipOut.setComment("hello");
if (file.isDirectory()) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; ++i) {
input = new FileInputStream(files[i]);
zipOut.putNextEntry(new ZipEntry(file.getName()
+ File.separator + files[i].getName()));
int temp = 0;
while ((temp = input.read()) != -1) {
zipOut.write(temp);
}
input.close();
}
}
zipOut.close();
}
}
ZipInputStream類解壓縮(包含多個文件的情況):
/**
* 解壓縮一個壓縮文件中包含多個文件的情況
*/
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("d:" + File.separator + "zipFile.zip");
File outFile = null;
ZipFile zipFile = new ZipFile(file);
ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));
ZipEntry entry = null;
InputStream input = null;
OutputStream output = null;
while ((entry = zipInput.getNextEntry()) != null) {
System.out.println("解壓縮" + entry.getName() + "文件");
outFile = new File("d:" + File.separator + entry.getName());
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdir();
}
if (!outFile.exists()) {
outFile.createNewFile();
}
input = zipFile.getInputStream(entry);
output = new FileOutputStream(outFile);
int temp = 0;
while ((temp = input.read()) != -1) {
output.write(temp);
}
input.close();
output.close();
}
}
}
SequenceInputStream 表示其他輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直到到達文件末尾,接著從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的文件末尾為止。
/**
* 文件合並
*/
public class Test {
public static void main(String[] args) throws IOException {
//定義輸出
FileOutputStream fos = new FileOutputStream("d:\\aaa\\d.txt");
//將一組流添加到list中
ArrayList al = new ArrayList();
al.add(new FileInputStream("d:\\aaa\\a.txt"));
al.add(new FileInputStream("d:\\aaa\\b.txt"));
al.add(new FileInputStream("d:\\aaa\\c.txt"));
//將list轉換為Enumeration
Enumeration en = Collections.enumeration(al);
//創建序列流讀入對象
SequenceInputStream sis = new SequenceInputStream(en);
//創建緩沖字節數組
byte[] buf = new byte[1024];
int len = 0;
//循環讀取字節數據
while ((len = sis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
//關閉流
sis.close();
fos.close();
}
}
/**
* 文件切割
*/
public class Test {
public static void main(String[] args) throws IOException {
splitFile();
}
public static void splitFile() throws IOException {
/*
* 有一個較大源讀取文件
* 創建讀取的文件對象
*/
File file = new File("d:\\aaa\\y.rmvb");
//創建讀入流對象
FileInputStream fis = new FileInputStream(file);
//創建寫出流對象
FileOutputStream fos = null;
//切割文件大小
byte[] buf = new byte[1024 * 1024 * 10];
int count = 0;
int len = 0;
//循環切割
while ((len = fis.read(buf)) != -1) {
count++;
//創建寫出流
fos = new FileOutputStream(new File(file.getParent() + "\\" + count + ".part"));
//寫出數據
fos.write(buf, 0, len);
//關閉寫出流
fos.close();
}
//關閉讀入流
fis.close();
}
}
ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化。
ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一起使用時,可以為應用程序提供對對象圖形的持久存儲。ObjectInputStream 用於恢復那些以前序列化的對象。其他用途包括使用套接字流在主機之間傳遞對象,或者用於編組和解組遠程通信系統中的實參和形參。
ObjectOutputStream 將 Java 對象的基本數據類型和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構)對象。通過在流中使用文件可以實現對象的持久存儲。如果流是網絡套接字流,則可以在另一台主機上或另一個進程中重構對象。
將支持 java.io.Serializable 接口的對象寫入流中。每個 serializable 對象的類都被編碼,編碼內容包括類名和類簽名、對象的字段值和數組值,以及從初始對象中引用的其他所有對象的閉包。
public class Test {
public static void main(String[] args) throws IOException {
//創建讀入寫出流對象
FileOutputStream outputStream = new FileOutputStream("hello.obj");
FileInputStream inputStream = new FileInputStream("hello.obj");
//創建對象讀入寫出流對象
ObjectOutputStream objOut = new ObjectOutputStream(outputStream);
ObjectInputStream objIn = new ObjectInputStream(inputStream);
//創建一個Person對象
Person person = new Person("Alice", 20);
//把person對象寫入對象流中
objOut.writeObject(person);
//讀入person對象
Person object = null;
try {
object = (Person) objIn.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(person.getName() + " : " + person.getAge());
}
}
//定義Person類,要想實現序列化,必須實現Serializable接口
class Person implements Serializable {
//顯示指定serialVersionUID,防止由於JDK版本不對而出現序列化操作失敗的問題
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Properties 類表示了一個持久的屬性集。Properties 可保存在流中或從流中加載。屬性列表中每個鍵及其對應值都是一個字符串。
Properties配置文件:
/**
* Properties配置存儲為文件
*/
public class Test {
public static void main(String[] args) throws IOException{
Properties prop = new Properties();
prop.setProperty("zhangsan", "15000");
prop.setProperty("lisi", "8000");
prop.setProperty("wangwu", "20000");
//prop.list(System.out);//測試用
prop.store(new FileOutputStream("a.properties"), "configuration");
prop.setProperty("wangwu", "10000");
System.out.println(prop.getProperty("wangwu"));
}
}
/**
* Properties
*/
public class Test {
public static void main(String[] args) throws IOException {
//獲取系統配置信息
Properties properties = System.getProperties();
System.out.println(properties.toString());
//將配置信息打印到控制台
//list方法經常用來調試,當前配置中的所有配置
properties.list(System.out);
//設置配置信息(自定義的配置)
Properties prop = new Properties();
prop.setProperty("zhangsan", "15000");
prop.setProperty("lisi", "18000");
prop.setProperty("wangwu", "8000");
prop.list(System.out);
String s = prop.getProperty("lisi");
System.out.println(s);
//獲取全部配置信息(使用集合遍歷)
Set props = prop.stringPropertyNames();
for (String key : props) {
System.out.println(key + " -> " + prop.getProperty(key));
}
//讀取配置文件中的配置信息
Properties prop2 = new Properties();
//把配置信息輸出到文件
FileInputStream is =new FileInputStream("salary.properties");
//加載文件中的配置信息到prop2中
prop2.load(is);
String ss = prop2.getProperty("zhangsan");
System.out.println(ss);
//控制台打印
prop2.list(System.out);
}
}
/**
* File類的用法
*/
public class Test {
public static void main(String[] args) {
//實例化對象時,文件不會產生
//File(String pathname)
File file = new File("d:\\abc.txt");
File file1 = new File("d:\\");
//同一個分區的多個文件操作 多個分區的同一個文件
// File(String parent, String child)
File file2 = new File("d:\\","abc.txt");
// File(File parent, String child)
File path = new File("d:\\");
File file3 = new File(path,"abc.txt");
System.out.println(File.separator); // System.getProperty("file.separator")
System.out.println(File.separatorChar); // System.getProperty("file.separator")
System.out.println(System.getProperty("file.separator"));
System.out.println(File.pathSeparator); //
}
}
/**
* 打印一個文件的所有屬性
*/
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("d:\\cd.txt");
System.out.println("getAbsolutePath = " + file.getAbsolutePath()); //絕對路徑
System.out.println("getName=" + file.getName()); //文件名
System.out.println("getCanonicalPath=" + file.getCanonicalPath()); //絕對路徑的規范形式
System.out.println("getPath=" + file.getPath()); //定義文件路徑時 內容是什麼就打印什麼
System.out.println("length=" + file.length()); //文件大小
System.out.println("lastModified=" + file.lastModified()); //最後修改時間
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long t = file.lastModified();
String time = sdf.format(t);
System.out.println(time);
}
}
/**
* 文件合並、文件分割、配置文件使用
*/
public class Test {
public static void main(String[] args) throws IOException {
//指定需要切割的文件
File filein = new File("D:\\aaa\\y.rmvb");
//指定合並後的目錄
File fileout = new File("D:\\bbb");
//切分
//split_file(filein);
//合並
merge_file(new File(filein.getParent()), fileout);
}
/**
* 合並文件
*
* @param fileout :合並後的目錄
* @param filein :合並前的目錄
* @throws IOException
*/
public static void merge_file(File filein, File fileout) throws IOException {
/* 獲取配置文件信息*/
Properties prop = new Properties();
File[] propFiles = filein.listFiles(new MyFilenameFilter(".properties"));
/*校驗部分*/
if (propFiles.length != 1) {
//此地默認切分生成目錄中只有一個配置文件 如果有多個配置文件 不予合並
throw new RuntimeException("配置文件不存在或者不唯一");
}
//將取到的唯一的配置文件加載到Properties對象中
prop.load(new FileInputStream(propFiles[0]));
//遍歷並查找文件切分後的文件
File[] listFiles = filein.listFiles(new MyFilenameFilter(".part"));
//判斷文件個數是否等於切分時寫入配置文件中的個數
if (listFiles.length != Integer.parseInt(prop.getProperty("filesplitnum"))) {
throw new RuntimeException("文件缺失!");
}
/*合並部分*/
//最終輸出的文件名 從配置文件中讀取 合並到fileout中
FileOutputStream fos = new FileOutputStream(new File(fileout, prop.getProperty("filename")));
//定義一個容器
ArrayList al = new ArrayList();
for (File file : listFiles) {
al.add(new FileInputStream(file));
}
//將ArrayList中轉換為Enumeration
Enumeration en = Collections.enumeration(al);
//使用序列流合並
SequenceInputStream sis = new SequenceInputStream(en);
//開始合並
byte[] buf = new byte[1024];
int len = 0;
while ((len = sis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
/* 資源釋放部分*/
//關閉流
sis.close();
fos.close();
}
/**
* 切割文件
* 參數一 file: 傳遞進來需要切割的文件
*
* @throws IOException
*/
public static void split_file(File file) throws IOException {
//讀取原來的大文件
FileInputStream fis = new FileInputStream(file);
//定義輸出流
FileOutputStream fos = null;
//獲取需要切割的文件的所在路徑 並將路徑封裝成為一個File對象
File path = new File(file.getParent());
byte[] buf = new byte[1024*1024 * 30];
int len = 0;
int count = 0;
while ((len = fis.read(buf)) != -1) {
fos = new FileOutputStream(new File(path, (count++) + ".part"));
fos.write(buf, 0, len);
fos.close();
}
//寫配置文件
Properties prop = new Properties();
prop.setProperty("filename", file.getName());
prop.setProperty("filesplitnum", count + "");
//將配置對象存儲到配置文件中
prop.store(new FileOutputStream(new File(path, file.getName() + ".properties")), "file split infos");
//關閉流
fis.close();
}
}
FilenameFilter:
FileFilter 是一個抽象類,JFileChooser 使用它過濾顯示給用戶的文件集合
FilenameFilter:
實現此接口的類實例可用於過濾器文件名。Abstract Window Toolkit 的文件對話框組件使用這些實例過濾 File 類的 list 方法中的目錄清單。
public class Test {
public static void main(String[] args) {
File file = new File("d:\\abc");
//通過過濾器過濾文件和目錄,返回抽象路徑名數組
String[] names = file.list(new MyFilenameFilter("d"));
//遍歷這些路徑名字符串
for (String name : names) {
System.out.println(name);
}
}
}
//實現自己的過濾器
public class MyFilenameFilter implements FilenameFilter {
private String suffix;
MyFilenameFilter(String suffix) {
this.suffix = suffix;
}
@Override
//重寫父類accept方法,實現自己的過濾器
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
/**
* 找出指定文件夾下的隱藏文件 和 指定文件擴展名文件
*/
public class Test {
public static void main(String[] args) {
File file = new File("F:\\電影");
// 返回抽象路徑名數組,這些路徑名表示此抽象路徑名表示的目錄中滿足指定過濾器的文件和目錄。
File[] listFiles = file.listFiles(new MyFileFilter(".mkv"));
//遍歷這些文件對象
for (File f : listFiles) {
System.out.println(f);
}
}
}
//自己的構造器類
class MyFileFilter implements FileFilter{
/*
* 要隱藏文件 要指定擴展名
*/
private String suffix;
MyFileFilter(String suffix){
this.suffix = suffix;
}
@Override
//重寫父類的accept方法,實現自己的業務邏輯
public boolean accept(File pathname) {
return pathname.getName().endsWith(suffix) && !pathname.isHidden();
}
}
文件遍歷:
/**
* 深度遍歷文件夾
*/
public class Test {
public static void main(String[] args) {
File file = new File("D:\\a");
listAll_3(file, 0);
}
//添加目錄縮進
public static void listAll_3(File file, int count) {
System.out.println(addSpace(count) + file);
//每調用一次加一次
count++;
File[] listFiles = file.listFiles();
for (int i = 0; i < listFiles.length; i++) {
//如果是目錄
if (listFiles[i].isDirectory()) {
listAll_3(listFiles[i], count);
} else {//是文件
System.out.println(addSpace(count) + listFiles[i]);
}
}
}
//在文件夾前面添加空格
public static String addSpace(int count) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++) {
sb.append("\t");
}
return sb.toString();
}
/**
* 列出目錄中文件
*/
public class Test {
public static void main(String[] args) {
File file = new File("D:\\abc");
//返回文件對象的目錄下所有文件名稱的字符串
String[] list = file.list();
//遍歷這些文件名稱字符串
for (String name : list) {
//篩選出以.java結尾的文件
if (name.endsWith(".java")) {
System.out.println(name);
}
}
}
}
/**
* 獲取指定目錄下,指定擴展名的文件(包含子目錄中的),將獲取到的文件絕對路徑按照關鍵詞過濾,存儲到UTF-8格式文本文件中。
*/
public class Test {
public static void main(String[] args) {
//需要查找的路徑
File path = new File("D:\\a");
File outpath = new File("D:\\aa.txt");
//定義一個容器
List list = new ArrayList();
//定義一個文件名過濾器
MyFilenameFilter filter = new MyFilenameFilter(".txt");
//查找
findFiles(path, list, filter);
//關鍵詞
String suffix = "a";
//寫結果集
writeFiles(list, outpath, suffix);
}
/**
* 寫結果集
*
* @param list 結果集
* @param outpath 輸出目錄
* @param suffix 關鍵詞
*/
public static void writeFiles(List list, File outpath, String suffix) {
if (list.size() == 0) {
return;
}
BufferedWriter bfw = null;
try {
//指定寫入路徑
bfw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outpath), "utf-8"));
//遍歷結果集 寫
for (String path : list) {
if (path.contains(suffix)) {
bfw.write(path);
bfw.newLine();
bfw.flush();
}
}
} catch (IOException e) {
throw new RuntimeException("寫入失敗 error :" + e.toString());
} finally {
//關閉流
if (bfw != null) {
try {
bfw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 找到符合條件的文件名
* args:path為傳遞進來文件夾路徑
*
*/
public static void findFiles(File path, List list, MyFilenameFilter filter) {
//判斷傳遞進來的路徑是否存在
if (!path.exists()) {
return;
}
//根據條件進行過濾
File[] rsList = path.listFiles(); //目錄下所有的內容查找出來
if (rsList.length > 0) {
//遍歷
for (File file : rsList) {
if (file.isDirectory()) {//是目錄
//遞歸
findFiles(file, list, filter);
} else {
//過濾文件擴展名
if (filter.accept(file, file.getName())) {
list.add(file.getAbsolutePath());
}
}
}
}
}
}
/**
* 遞歸刪除文件夾
*/
public class Test {
public static void main(String[] args) {
File file = new File("D:\\aa");
deletedir(file);
}
public static void deletedir(File file) {
//列出;路徑下的文件及文件夾
File[] listFiles = file.listFiles();
//遍歷刪除
for(int i = 0 ; i < listFiles.length ; i++){
if(listFiles[i].isDirectory()){//如果是目錄
deletedir(listFiles[i]);
listFiles[i].delete();
}else{
//不管是目錄或者是文件都嘗試刪一下
listFiles[i].delete();
}
}
//刪除頂級文件夾
file.delete();
}
}
/**
* 實現創建並刪除文件夾或者一個文件
*/
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("D:\\bbb.txt");
//文件創建
//創建一個新的文件 如果文件存在 不創建
boolean b = file.createNewFile();
//虛擬機退出時刪除文件
file.deleteOnExit();
//創建不存在的一級目錄
boolean b1 = file.mkdir();
//創建不存在的多級目錄
boolean b2 = file.mkdirs();
//刪除文件或文件夾,當文件夾非空,會出問題
boolean b3 = file.delete();
System.out.println(b);
}
}
System.in:
/**
* 讀取鍵盤輸入的數據 打印到控制台上
*/
public class Test {
public static void main(String[] args) throws IOException {
//獲取鍵盤輸入的數據
InputStream in = System.in;
int ch = 0;
//循環讀取輸入的數據直到末尾
while ((ch = in.read()) != -1) {
//將讀取的字節流顯示轉化為字符
System.out.print((char) ch);
}
}
}
System.out:
/**
* 實現一個打印程序
*/
public class Test {
public static void main(String[] args) throws IOException {
OutputStream out = System.out;
out.write("abcd".getBytes());
}
}
/**
* 將用戶輸入的數據寫入到文本文件中
*/
public class Test {
public static void main(String[] args) throws IOException {
//輸出目的源
FileOutputStream fos = new FileOutputStream("d:\\a.txt");
BufferedOutputStream bfos = new BufferedOutputStream(fos);
//獲取用戶終端輸入的數據
InputStream in = System.in;
//使用高效讀取
BufferedInputStream bin = new BufferedInputStream(in);
int ch = 0;
//循環讀取字節
while ((ch = bin.read()) != -1) {
bfos.write(ch);
//刷新緩沖區
bfos.flush();
}
}
}
/**
* 將文本文件中的內容打印到控制台上
*/
public class Test {
public static void main(String[] args)throws IOException {
//讀取源
FileInputStream fis =new FileInputStream("d:\\a.txt");
OutputStream out = System.out;
int ch = 0;
while ((ch = fis.read()) != -1) {
out.write(ch);
}
fis.close();
}
}
/**
* 使用轉換流實現輸入字符轉大寫的打印功能
*/
public class Test {
public static void main(String[] args)throws IOException {
read_console();
}
public static void read_console()throws IOException {
InputStream in = System.in;
// 字節流轉換為字符流
InputStreamReader isr =new InputStreamReader(in);
BufferedReader bfr = new BufferedReader(isr);
String line = null;
while ((line = bfr.readLine()) !=null) {
if ("exit".equals(line)) {
return;
}
System.out.println(line.toUpperCase());
}
isr.close();
bfr.close();
}
}