javaIO位元組流和字元流
流的概念
程式中的輸入輸出都是以流的形式儲存的,流中儲存的實際都是位元組檔案
位元組流與字元流
內容操作就四個類:OutputStream、InputStream、Writer、Reader
操作流程
使用File類操作的時候一定要有路徑,請注意分隔符。
實際上四個操作類都是抽象類
IO操作屬於資源操作,對於資源操作,最後必須關閉,否則可能出現位置的錯誤
位元組流
Byte是位元組,肯定使用位元組流操作,所有的資料基本上都可以直接使用Byte陣列表示出來。
位元組輸出流:OutputStream
Clonseable表示關閉的操作,因為程式執行最後肯定要關閉。
Flush表示重新整理,清空記憶體中的資料。
OutputStream類的常用方法
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class OutputStreamDemo01 { public static void main(String[] args) throws Exception{ //丟擲異常不處理 //第一步,使用File類找到一個檔案 File f = new File("d:" + File.separator + "test.txt"); //宣告File物件 //第二步,通過子類例項化父類物件 OutputStream out = null; out = new FileOutputStream(f); //第三步,進行寫操作 String str = "Hello world"; //準備一個字串 byte b[] = str.getBytes(); //只能輸出byte陣列,所以將字串變為byte陣列 out.write(b); //第四步,關閉輸出流 out.close(); }
}
在操作的時候,如果檔案本身不存在,則會為使用者建立一個檔案
在操作輸出流的時候,也可以使用write(int i)的方法寫出資料
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class OutputStreamDemo02 { public static void main(String[] args) throws Exception{ //丟擲異常不處理 //第一步,使用File類找到一個檔案 File f = new File("d:" + File.separator + "test.txt"); //宣告File物件 //第二步,通過子類例項化父類物件 OutputStream out = null; out = new FileOutputStream(f); //第三步,進行寫操作 String str = "Hello world"; //準備一個字串 byte b[] = str.getBytes(); //只能輸出byte陣列,所以將字串變為byte陣列 for(int i = 0;i < b.length;i++) { out.write(i); } //第四步,關閉輸出流 out.close(); }
}
在以上的操作在寫入資料之後,檔案之前的內容已經不存在了,因為IO操作預設的情況是將其進行覆蓋,那麼現在如果想要執行追加的功能,則必須設定追加的操作,找到FileOutputStream類。
追加新內容
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo03 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
OutputStream out = null; //準備好一個輸出的物件
out = new FileOutputStream(f,true); //此處表示在末尾追加內容
//第三步,進行寫操作
String str = "Hello world"; //準備一個字串
byte b[] = str.getBytes(); //只能輸出byte陣列,所以將字串變為byte陣列
for(int i = 0;i < b.length;i++) {
out.write(b[i]);
}
//第四步,關閉輸出流
out.close();
}
}
程式本身是可以追加內容了,但是沒有換行,是直接在末尾追加的。
如果在檔案操作中想要換行的話,使用\r\n完成
位元組輸入流:InputStream
InputStream類的常用方法
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo01 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
InputStream in = null; //準備好一個輸入的物件
in = new FileInputStream(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
byte b[] = new byte[1024];
in.read(b);
//第四步,關閉輸出流
in.close();
System.out.println("內容為:" + new String(b)); //把byte陣列變為字串輸出
}
}
此時,內容確實已經讀取進來了,但是可以發現存在的問題。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo02 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
InputStream in = null; //準備好一個輸入的物件
in = new FileInputStream(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
byte b[] = new byte[1024];
int len = in.read(b);
//第四步,關閉輸出流
in.close();
System.out.println("讀取內容的長度:" + len);
System.out.println("內容為:" + new String(b,0,len)); //把byte陣列變為字串輸出
}
}
程式碼還是存在問題,現在檔案沒有這麼大,但是開闢了這麼大的陣列空間,這樣一定會浪費空間,能不能根據檔案的大小開闢陣列空間呢?
如果想要知道檔案大小,直接使用File類即可。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo03 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
InputStream in = null; //準備好一個輸入的物件
in = new FileInputStream(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
byte b[] = new byte[(int)f.length()]; //陣列的大小由檔案決定
int len = in.read(b);
//第四步,關閉輸出流
in.close();
System.out.println("讀取內容的長度:" + len);
System.out.println("內容為:" + new String(b,0,len)); //把byte陣列變為字串輸出
}
}
以上直接使用byte陣列的方式完成的
現在使用read方法讀取內容。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo04 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File(“d:” + File.separator + “test.txt”); //宣告File物件
//第二步,通過子類例項化父類物件
InputStream in = null; //準備好一個輸入的物件
in = new FileInputStream(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
byte b[] = new byte[(int)f.length()]; //陣列的大小由檔案決定
for(int i = 0;i < b.length;i++) {
b[i] = (byte)in.read(); //讀取內容
}
int len = in.read(b);
//第四步,關閉輸出流
in.close();
System.out.println("讀取內容的長度:" + len);
System.out.println("內容為:" + new String(b)); //把byte陣列變為字串輸出
}
}
以上的操作,只適合於知道輸入流的大小的時候。如果不知道大小呢?
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo04 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File(“d:” + File.separator + “test.txt”); //宣告File物件
//第二步,通過子類例項化父類物件
InputStream in = null; //準備好一個輸入的物件
in = new FileInputStream(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
byte b[] = new byte[1024]; //陣列的大小由檔案決定
int len = 0;
int temp = 0; //接受每一個讀進來的資料
while((temp=in.read()) != -1) {
//表示還有內容,檔案沒有讀完
b[len] = (byte)temp;
len++;
}
//第四步,關閉輸出流
in.close();
System.out.println("讀取內容的長度:" + len);
System.out.println("內容為:" + new String(b,0,len)); //把byte陣列變為字串輸出
}
}
當不知道讀取內容有多大的時候,就只能以讀取的資料是否為-1為讀完的標誌。
字元流
字元輸入流:Write類
Write類常用的方法
字元流的操作比位元組流操作好一些,就是可以直接輸出字串了,不用再像之前那樣進行轉換操作。
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo01 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
Writer out = null;
out = new FileWriter(f);
//第三步,進行寫操作
String str = "Hello world"; //準備一個字串
out.write(str);
//第四步,關閉輸出流
out.close();
}
}
使用位元組流預設情況下依然是覆蓋已經有的檔案,如果想要追加的話,則直接在FileWriter上增加一個可追加標記即可。
字元輸入流:Reader類
Reader類的常用方法
以字元陣列的形式讀取資料
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo01 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
Reader in = null; //準備好一個輸入的物件
in = new FileReader(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
char b[] = new char[1024];
int len = in.read(b);
//第四步,關閉輸出流
in.close();
System.out.println("內容為:" + new String(b,0,len)); //把字元陣列變為字串輸出
}
}
也可以使用迴圈方法,通過檔案是否讀到底的形式讀取;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo02 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
Reader in = null; //準備好一個輸入的物件
in = new FileReader(f); //通過物件多型性,進行例項化
//第三步,進行讀操作
char b[] = new char[1024];
int temp = 0; //接受每個內容
int len = 0;
while((temp=in.read())!=-1) {
b[len] = (char)temp;
len++;
}
//第四步,關閉輸出流
in.close();
System.out.println("內容為:" + new String(b,0,len)); //把字元陣列變為字串輸出
}
}
位元組流與字元流的區別
位元組流和字元流的使用是非常相似的,那麼除了操作程式碼的不同之外,還有那些不同呢?
通過一個程式碼驗證字元流使用到了快取。
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo05 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
OutputStream out = null; //準備好一個輸出的物件
out = new FileOutputStream(f); //例項化
//第三步,進行寫操作
String str = "Hello world"; //準備一個字串
byte b[] = str.getBytes(); //只能輸出byte陣列,所以將字串變為byte陣列
out.write(b);
}
}
在使用位元組流操作中,及時沒有關閉,最終也是可以輸出的。
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo03 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
Writer out = null;
out = new FileWriter(f);
//第三步,進行寫操作
String str = "Hello world"; //準備一個字串
out.write(str);
}
}
以上的操作,沒有輸出任何的內容出來,也就是說,所有的內容都是儲存在了快取區中,而如果執行關閉的時候會強制性的重新整理緩衝區,所以可以把內容輸出。
如果現在假設沒有關閉的話,可以強制呼叫重新整理方法 。
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo04 {
public static void main(String[] args) throws Exception{ //丟擲異常不處理
//第一步,使用File類找到一個檔案
File f = new File("d:" + File.separator + "test.txt"); //宣告File物件
//第二步,通過子類例項化父類物件
Writer out = null;
out = new FileWriter(f);
//第三步,進行寫操作
String str = "Hello world"; //準備一個字串
out.write(str);
//強制性清空快取區中的內容
out.flush();
}
}
問題:
開發中是使用位元組流好還是字元流好
在所有的硬碟上儲存檔案或是進行傳輸的時候都是以位元組的方式進行的。包括圖片也是按位元組完成,而字元是隻有在記憶體中才會形成的,所以使用位元組的操作是最多的。
操作範例
操作的時候可以按照如下的格式進行
javaCopy原始檔
如果要採用以上的格式,則肯定要使用初始化引數的形式,輸入兩個路徑,所以,此時就必須對輸入引數的個數進行驗證,判斷是否為2
是使用位元組流還是字元流呢?肯定使用位元組流,因為萬一拷貝的是一個圖片。
要完成拷貝程式,有兩種方式可以採用
實現1:將原始檔中的內容全部讀取進來,之後一次性寫入到目標檔案
實現2:邊讀邊寫的方式
很明顯使用第二種方式