在上一個剛剛介紹了File類,創建了文件或者文件夾,但是裏面的數據是怎麼操作它呢,若想操作文件中的數據,需要藉助字節流或者字符流。
字節流
字節流是由字節組成的,字符流是由字符組成的.
IO流的分類
- 字節流
- 字節輸入流 InputStream 抽象類
- FileInputStream 操作文件的字節輸入流
- 字節輸出流 OuputStream抽象類
-FileOutputStream 操作文件的字節輸出流
- 字符流
- 字符輸入流 Reader抽象類
- InputStreamReader 輸入操作的轉換流
- FileReader 用來操作文件的字符輸入流(簡便的流)
- 字符輸出流 Writer抽象類
- OutputStreamWriter 輸出操作的轉換流
- FileWriter 用來操作文件的字符輸出流(簡便的流)
字節輸出流OutputStream
OuputStream是一個抽象類,表示輸出字節流的所有類的超類,操作的數據都是字節,字節流處理單元爲一個字節。
使用OuputStream該抽象類的子類如FileOutputStream、ObjectOutputStream.
字節輸出流中定義的方法主要爲write方法,如:
void write(byte[] b);//將b.length個字節從指定的byte數組寫入此輸出流。
void write(byte[] b,int off,int len);//將指定的byte數組中從偏移量off開始的冷個字節寫入此輸出流。
abstract void write(int b);//將指定的字節寫入此輸出流。
FileOutputStream類
即文件輸出流,是用於將數據寫入 File
的輸出流。
構造方法
FileOutputStream(File file);//創建一個向指定File對象表示的文件中寫入數據的文件輸出流
FileOutputStream(String name);//創建一個向指定路徑名字符串表示的文件中寫入數據的文件輸出流
實例-寫入數據到文件中:
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//需求:將數據寫入到文件中。
//創建存儲數據的文件。
File file = new File("c:\\file.txt");
//創建一個用於操作文件的字節輸出流對象。一創建就必須明確數據存儲目的地。
//輸出流目的是文件,會自動創建。如果文件存在,則覆蓋。
FileOutputStream fos = new FileOutputStream(file);//使用傳入File對象的構造方法
//調用父類中的write方法。
byte[] data = "abcde".getBytes();//使用String類中的getBytes方法將String對象變爲Byte數組
fos.write(data);
//關閉流資源。
fos.close();
}
}
在實際開發中,創建一個文件並向該文件內寫入數據,並關掉,可能會發生異常。實例代碼
public class FileOutputStreamDemo3 {
public static void main(String[] args) {
File file = new File("c:\\file.txt");
//定義FileOutputStream的引用
FileOutputStream fos = null;
try {
//創建FileOutputStream對象
fos = new FileOutputStream(file);
//寫出數據
fos.write("abcde".getBytes());
} catch (IOException e) {
System.out.println(e.toString() + "----");
} finally {
//一定要判斷fos是否爲null,只有不爲null時,纔可以關閉資源
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("");
}
}
}
}
}
字節輸入流InputStream
特點是從內存將文件中的數據讀出,InputStream可以實現,該類仍爲抽象類,是表示字節數入流的所有類的超類,使用它的子類如:FileInputStream,ObjectInputStream。
FileInputStream從文件系統中的某個文件中獲得輸入字節,
FileInputStream類的構造方法
FileInputStream(File file)
通過打開一個到實際文件的連接來創建一個
FileInputStream
,該文件通過文件系統中的 File
對象 file
指定。
FileInputStream(String name)
通過打開一個到實際文件的連接來創建一個
FileInputStream
,該文件通過文件系統中的路徑名 name
指定。
FileInputStream主要方法:
int read();//從輸入流中讀取的下一個字節,一次只能讀一個字節。
int read(byte[] b);//從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。
int read(byte[] b,int off,int len);//將輸入流中最多 len 個數據字節讀入 byte 數組。
1.使用read()方法實例:
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
File file = new File("c:\\file.txt");
//創建一個字節輸入流對象,必須明確數據源,其實就是創建字節讀取流和數據源相關聯。
FileInputStream fis = new FileInputStream(file);
//讀取數據。使用 read();一次讀一個字節。
int ch = 0;
while((ch=fis.read())!=-1){
System.out.println("ch="+(char)ch);
}
// 關閉資源。
fis.close();
}
}
此方法缺點在於讀取大文件時,速度太慢。
2. 使用read(byte[ ])方法實例:
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
* 演示第二個讀取方法, read(byte[]);
*/
File file = new File("c:\\file.txt");
// 創建一個字節輸入流對象,必須明確數據源,其實就是創建字節讀取流和數據源相關聯。
FileInputStream fis = new FileInputStream(file);
//創建一個字節數組。
byte[] buf = new byte[1024];//長度可以定義成1024的整數倍。
int len = 0;
while((len=fis.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
fis.close();
}
}
讀取是通過創建一個字節數組,讀取一個字節數組的大小再寫入程序中,此方法的優勢在於速度快。
3. 使用字節緩衝輸入流BufferedInputStream實例:
/*
* 從文件中讀取數據
* 1,創建緩衝流對象
* 2,讀數據,打印
* 3,關閉
*/
private static void read() throws IOException {
//1,創建緩衝流對象
FileInputStream fileIn = new FileInputStream("abc.txt");
//把基本的流包裝成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
//2,讀數據
int ch = -1;
while ( (ch = in.read()) != -1 ) {
//打印
System.out.print((char)ch);
}
//3,關閉
in.close();
}
使用字節流實現複製文件
原理是讀取一個已有的數據,並將這些數據寫入到另一個文件中。
public class CopyFileTest {
public static void main(String[] args) throws IOException {
//1,明確源和目的。
File srcFile = new File("c:\\YesDir\test.JPG");
File destFile = new File("copyTest.JPG");
//2,明確字節流 輸入流和源相關聯,輸出流和目的關聯。
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//3, 使用輸入流的讀取方法讀取字節,並將字節寫入到目的中。
int ch = 0;
while((ch=fis.read())!=-1){
fos.write(ch);
}
//4,關閉資源。
fos.close();
fis.close();
}
}
上述代碼輸入流和輸出流之間是通過ch這個變量進行數據交換的。
上述複製文件有個問題,每次都從源文件讀取一個,然後在寫到指定文件,接着再讀取一個字符,然後再寫一個,一直這樣下去。效率極低。
使用緩衝數組方式複製文件
public class CopyFileByBufferTest {
public static void main(String[] args) throws IOException {
File srcFile = new File("c:\\YesDir\test.JPG");
File destFile = new File("copyTest.JPG");
// 明確字節流 輸入流和源相關聯,輸出流和目的關聯。
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//定義一個緩衝區。
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);// 將數組中的指定長度的數據寫入到輸出流中。
}
// 關閉資源。
fos.close();
fis.close();
}
}
在進行過讀取文件中數據的操作,讀取數據量大的文件時,讀取的速度會很慢,很影響我們程序的效率,Java中提高了一套緩衝流,它的存在,可提高IO流的讀寫速度。
緩衝流,根據流的分類分類字節緩衝流與字符緩衝流。
字節緩衝流:
1. 字節緩衝輸出流 BufferedOutputStream
2. 字節緩衝輸入流 BufferedInputStream
它們的內部都包含了一個緩衝區,通過緩衝區讀寫,就可以提高了IO流的讀寫速度
1. 字節緩衝輸出流 BufferedOutputStream
構造方法:
BufferedOutputStream(OutputStream out);//創建一個新的緩衝輸出流,以將數據寫入指定的底層輸出流。
BufferedOutputStream(OutputStream out,int size);//創建一個新的緩衝輸出流,以將具有指定緩衝區大小的數據寫入指定的底層輸出流。
其參數爲:字節輸出流的對象
實例:
public class BufferedOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//寫數據到文件的方法
write();
}
/*
* 寫數據到文件的方法
* 1,創建流
* 2,寫數據
* 3,關閉流
*/
private static void write() throws IOException {
//創建基本的字節輸出流
FileOutputStream fileOut = new FileOutputStream("abc.txt");
//使用高效的流,把基本的流進行封裝,實現速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//2,寫數據
out.write("hello".getBytes());
//3,關閉流
out.close();
}
}
2. 字節緩衝輸入流 BufferedInputStream
構造方法
public BufferedInputStream(InputStream in);//創建一個
BufferedInputStream
並保存其參數,即輸入流 in
,以便將來使用。
public BufferedInputStream(InputStream in,size);//創建具有指定緩衝區大小的
BufferedInputStream
並保存其參數,即輸入流 in
,以便將來使用。
其參數爲字節輸入流的對象。
實例:
/*
* 從文件中讀取數據
* 1,創建緩衝流對象
* 2,讀數據,打印
* 3,關閉
*/
private static void read() throws IOException {
//1,創建緩衝流對象
FileInputStream fileIn = new FileInputStream("abc.txt");
//把基本的流包裝成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
//2,讀數據
int ch = -1;
while ( (ch = in.read()) != -1 ) {
//打印
System.out.print((char)ch);
}
//3,關閉
in.close();
}
使用基本的流與高效的流完成複製文件
我們一直在說,高效的流速度快並高效,怎麼體現呢?需要通過一個複製文件耗時的比較過程,來體驗一下高效流帶來的快感。/*
* 需求:將d:\\test.avi文件進行復制
* 採用4種方式複製
* 方式1: 採用基本的流,一次一個字節的方式複製 共耗時 224613毫秒
* 方式2: 採用基本的流,一個多個字節的方式賦值 共耗時 327毫秒
* 方式3: 採用高效的流,一次一個字節的方式複製 共耗時 2047毫秒
* 方式4: 採用高效的流,一個多個字節的方式賦值 共耗時 96毫秒
*
* 數據源: d:\\test.avi
* 目的地1: d:\\copy1.avi
* 目的地2: d:\\copy2.avi
* 目的地3: d:\\copy3.avi
* 目的地4: d:\\copy4.avi
*
* 實現的步驟:
* 1,指定數據源
* 2,指定目的地
* 3,讀數據
* 4,寫數據
* 5,關閉流
*
*/
public class CopyAVI {
public static void main(String[] args) throws IOException {
//開始計時
long start = System.currentTimeMillis();
//方式1: 採用基本的流,一次一個字節的方式複製
//method1("d:\\test.avi", "d:\\copy1.avi");
//方式2: 採用基本的流,一個多個字節的方式賦值
//method2("d:\\test.avi", "d:\\copy2.avi");
//方式3: 採用高效的流,一次一個字節的方式複製
//method3("d:\\test.avi", "d:\\copy3.avi");
//方式4: 採用高效的流,一個多個字節的方式賦值
method4("d:\\test.avi", "d:\\copy4.avi");
//結束計時
long end = System.currentTimeMillis();
//打印耗時多少毫秒
System.out.println("共耗時 " +(end - start)+ "毫秒");
}
//方式4: 採用高效的流,一個多個字節的方式賦值
private static void method4(String src, String dest) throws IOException {
//1,指定數據源
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//2,指定目的地
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//3,讀數據
byte[] buffer = new byte[1024];
int len = -1;
while ( (len = in.read(buffer)) != -1) {
//4,寫數據
out.write(buffer, 0, len);
}
//5,關閉流
in.close();
out.close();
}
//方式3: 採用高效的流,一次一個字節的方式複製
private static void method3(String src, String dest) throws IOException {
//1,指定數據源
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//2,指定目的地
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//3,讀數據
int ch = -1;
while ((ch=in.read()) != -1) {
//4,寫數據
out.write(ch);
}
//5,關閉流
in.close();
out.close();
}
//方式2: 採用基本的流,一個多個字節的方式賦值
private static void method2(String src, String dest) throws IOException {
//1,指定數據源
FileInputStream in = new FileInputStream(src);
//2,指定目的地
FileOutputStream out = new FileOutputStream(dest);
//3,讀數據
byte[] buffer = new byte[1024];
int len = -1;
while ( (len=in.read(buffer)) != -1) {
//4,寫數據
out.write(buffer, 0, len);
}
//5,關閉流
in.close();
out.close();
}
//方式1: 採用基本的流,一次一個字節的方式複製
private static void method1(String src, String dest) throws IOException {
//1,指定數據源
FileInputStream in = new FileInputStream(src);
//2,指定目的地
FileOutputStream out = new FileOutputStream(dest);
//3,讀數據
int ch = -1;
while (( ch=in.read()) != -1) {
//4,寫數據
out.write(ch);
}
//5,關閉流
in.close();
out.close();
}
}