IO流用來處理設備之間的數據傳輸。
- 流按流向分爲:輸入流、輸出流。
輸入流、輸出流相對於內存設備而言。將外設中的數據讀取到內存:輸入;將內存的數據寫入到外設中:輸出。 - 流按操作數據不同分爲兩種:字節流、字符流
字節流:通用流。
字符流:基於字節流。由來:字節流讀取文字字節數據後,不直接操作而是先查指定的編碼表,獲取對應的數字,在對該文字進行操作。
ASCII:英文編碼表
GB2312/GBK:中文編碼表
UTF-8:國際通用碼錶
如果對一臺計算機使用GBK編碼存儲,那麼另一臺UTF-8的機器無法識別正確的文字,並顯示亂碼。因此,字符流可以指定編碼方式來獲取對應的文字。
二、I/O流常用基類
字符流
字節流的抽象基類:InputStream,OutputStream
字符流的抽象基類:Reader,Writer
P.S. 有着四個類派生出的子類名稱都是以其父類名作爲子類名的後綴。如InputStream的子類FileInputStream,如Reader的子類FileReader。
需求:將一些文字存儲到硬盤一個文件中。
注意:如果要操作文字數據,建議優先考慮字符流。使用FileWriter。
import java.io.*;
class FileWriterDemo throws IOException {
public static void main(String[] args) {
//該文件會被創建到指定目錄下。如果文件存在,則會被覆蓋。
FileWriter fw = new FileWriter("demo.txt");
//將數據寫入到臨時存儲緩衝區中
fw.write("abcde");
//刷新該流的緩衝,將臨時存放的數據寫入到目的地
//如果不寫,則要等到緩衝區滿纔會寫入目的地
fw.flush();
//關閉流,關閉資源,釋放內存
fw.close();
}
}
I/O異常處理
import java.io.*
class FileWriterDemo2 {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
} catch(IOException e) {
System.out.println("catch:" + e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}
對已有文件的數據續寫
import java.io.*
class FileWriterDemo3 {
public static void main(String[] args) {
FileWriter fw = null;
try {
//true參數,代表不覆蓋已有的文件,在已有文件的末尾處進行數據讀寫
fw = new FileWriter("demo.txt", true);
fw.write("hello\r\n"thanks); //記事本中按\r\n換行
} catch (IOException e) {
System.out.println("catch:" + e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}
需求:讀取一個文件,將讀取到的字符打印到控制檯。
第一種讀取方式:read()方法讀取文本文件數據
import java.io.*
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
//創建一個文件讀取流對象
//如果文件不存在,會拋出FileNotFountException
FileReader fr = new FileReader("demo.txt");
//調用讀取流對象的read()方法
//read():一次讀一個字符,而且會自動往下讀。如果已到達流的末尾,則返回-1
int ch = 0;
while((ch = fr.read()) != -1) {
System.out.println((char)ch);
}
fr.close;
}
}
第二種讀取方式:使用read(char[])讀取文本文件數據
import java.io.*
public class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf,0,num));
}
fr.close;
}
}
打印一個.java文件,並打印在控制檯上
import java.io.*
class FileReaderTest throws IOException {
public static void main(String[] args) {
FileReader fr = new FileReader("DateDemo.java");
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf,0,num));
}
fr.close();
}
}
將C盤一個文本文件複製到D盤
複製的原理:將C盤下的文件數據存儲到D盤的一個文件中。
步驟:
1、在D盤創建一個文件,用於存儲C盤文件的數據
2、定義讀取流和C盤文件關聯
3、通過不斷讀寫完成數據存儲
4、關閉資源
import java.io.*
class CopyText throws IOException {
public static void main(String[] args) {
FileWriter fw = null;
FileReader fr = null;
try {
fw = new FileWriter("D:\\SystemDemo_copy.txt");
fr = new FileReader("C:\\SystemDemo.java");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf)) != -1) {
fw.write(buf,0,len);
}
} catch (IOException e) {
throw new RuntimeException("讀寫失敗");
} finally {
if(fr != null) {
try {
fr.close();
} catch(IOException e) {
e.printStackTrace();
}
}
if(fw != null) {
try {
fw.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
}
字符流的緩衝區
緩衝區的出現提高了對數據的讀寫效率。
對應的類:BufferedWriter,BufferedReader
寫入緩衝區
FileWriter fw = new FileWriter("buf.txt");
BufferedWriter bw = new BufferedWriter(fw);
for(int i=1; i<5; i++) {
bw.write("abcd" + x);
bw.newLine(); //跨平臺的換行符
bw.flush(); //只要用到緩衝區,就要刷新
}
//關閉緩衝區,就是在關閉緩衝區中的流對象,故不需要寫fw.close()
bw.close();
讀取緩衝區
FileReader fr = new FileReader("buf.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
使用緩衝區複製文本文件
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader("xxx.java"));
bw = new BufferedWriter(new FileWriter("xxx_copy.txt"));
String line = null;
while((len = br.readLine()) != null) {
bw.write(line);
bw.newLine(); //readLine方法返回時,只返回回車符之前的數據內容,並不返回回車符,故要加上newLine()
bw.flush();
}
} catch (IOException e) {
throw new RuntimeException("讀寫失敗");
} finally {
try {
if(br != null) {
br.close();
} catch(IOException e) {
throw new RuntimeException("讀取關閉失敗");
}
}
try {
if(bw != null) {
bw.close();
} catch(IOException e) {
throw new RuntimeException("寫入關閉失敗");
}
}
}
寫入換行使用BufferedWriter類中的newLine()方法。
讀取一行數據使用BufferedReader類中的readLine()方法。
原理: 使用了讀取緩衝區的read方法, 將讀取到的字符進行緩衝並判斷換行標記, 將標記前的緩衝數據變成字符串返回。
字節流
基本操作與字符流類相同。但它不僅可以操作字符,還可以操作其它媒體文件。
InputStream,OutputStream
需求:操作圖片數據
public static void writeFile throws IOException() {
FileOutputStream fos = new FileOutputStream("fos.txt");
//數據直接寫到了目的地中
fos.write("abcde".getBytes());
//字節流不需要刷新
fos.close();
}
public static void writeFile throws IOException() {
FileInputStream fis = new FileInputStream("xxx.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
fis.close();
}
複製一個圖片
思路:
1、用字節流讀取對象和圖片關聯
2、用字節寫入流對象創建一個圖片文件,用於存儲獲取到的圖片數據
3、通過循環讀寫,完成數據的存儲
4、關閉資源
class CopyPic {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("c:\\1.bmp");
fos = new FileOutputStream("c:\\2.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1) {
fos.write(buf,0,len);
}
} catch(IOException e) {
throw new RuntimeException("複製文件失敗");
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e){
throw new RuntimeException("讀取關閉失敗");
}
try {
if(fos != null)
fos.close();
} catch (IOException e){
throw new RuntimeException("寫入關閉失敗");
}
}
}
}
演示MP3的複製,通過緩衝區
BufferedOutputStream
BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by = bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
轉換流
InputStreamReader
字節流通向字符流的橋樑。解碼。在構造時接受一個字節流。
讀取轉換流:
需求:當錄入一行數據後,就將該行數據進行打印。如果錄入的數據是over,那麼停止錄入。
//獲取鍵盤錄入對象
InputStream in = System.in;
//將字節流轉換成字符流對象
InputStreamReader isr = new InputStreamReader(in);
//爲了提高效率,將字符串進行緩衝區技術高效操作,使用BufferedReader
BufferedReader br = new BufferedReader(isr);
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
br.close();
寫入轉換流:
OutputStreamWriter
字符通向字節的橋樑。編碼。在構造時接收一個輸出流。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush(); //務必寫上
}
br.close();
需求:將鍵盤錄入的數據寫入到一個文件中。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
需求:將一個文件的數據打印在控制檯上。
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("xxx.java")));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
流操作的基本規律
通過兩個明確來完成流對象的選擇:
1、明確源和目的。
源:輸入流 – InputStream Reader
目的:輸出流 – OutputStream Writer
2、操作的數據是否是純文本。
是:字符流
不是:字節流
3、當體系明確後,再明確使用哪個具體的對象。通過設備來進行區分。
源設備:內存、硬盤、鍵盤
目的設備:內存、硬盤、控制檯
需求1:複製一個文本文件
源:InputStream / Reader
是否操作文本文件?是。選擇Reader。
接下來明確要使用該體系中的哪個對象。
明確設備:硬盤上的文件
Reader體系中可以操作文件的對象是FileReader
是否需要提高效率?是。加入Reader體系中的緩衝區BufferedReader
FileReader fr = new FileReader(“a.txt”);
BufferedReader br = new BufferedReader(fr);
目的:OutputStream / Writer
是否純文本:是。選擇Writer
設備:硬盤上的文件
Writer體系中可以操作文件的對象是FileWriter.
是否需要提高效率?是。加入Writer體系中的緩衝區BufferedWriter
FileWriter fw = new FileWriter(“b.txt”);
BufferedWriter bw = new BufferedWriter(fw);
File類
用來將文件或文件夾封裝成對象的類,可以操作文件與文件夾的屬性信息。File對象可以作爲參數傳遞給流的構造函數。
流只能操作數據,如果要操作數據的文件對象,必須用到File對象。
File常用方法:
1、獲取
文件名稱getName()
文件路徑getPath(),getAbsolutePath
文件大小length()
文件修改時間lastModified()
2、創建和刪除
創建 boolean createNewFile()
刪除 delete()
3、判斷
是否可執行 canExcecute()
是否可讀 canRead()
是否可寫 canWrite()
是否存在 exists()
是否是文件 isFile()
是否是目錄 isDirectory()
打印流:該流提供了打印方法,可以將各種數據類型的數據都原樣打印。
字節打印流:PrintStream
構造函數可以接受的參數類型:
1、file對象。File
2、字符串路徑。String
3、字節輸出流。OutputStream
PrintStream永遠不會拋出IOException
字符打印流:PrintWriter
構造函數可以接受的參數類型:
1、file對象。File
2、字符串路徑。String
3、字節輸出流。OutputStream
4、字符輸出流。Writer
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("a.txt"), true)); //可以自動刷新
String line = null
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
out.println(line.toUpperCase());
//out.flush();
}
out.close();
br.close();
序列流SequenceInputStream
對多個流進行合併。
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1) {
fos.write(buf,0,len);
}
fos.close();
sis.close();
切割流
public static void merge() {
ArrayList<FileInputStream> a1 = new ArrayList<FileInputStream>();
for(int x=1; x<=3; x++) {
}
}
public static void splitFile() throws IOException {
FileInputStream fis = new FileInputStream("c:\\1.bmp");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];
int len = 0;
int count = 1;
while((len = fis.read(buf)) != -1) {
fos = new FileOutputStream("c:\\splitfiles\\"+(count++)".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}