第一部分:字符流
字符流=字節流+編碼表。
字符流是相對字節流來說的,由於一箇中文字符佔據了兩個字節,因此用字節流讀中文字符時,不如字符流處理中文效果好,因此在遇到文本情況時,能用字符流的最好用字符流。
1、編碼表:
由字符及其對應的數值組成的一張表:
這裏通過String類的構造函數及方法,來講述編碼表:
String (byte [] bytes,String charseName):通過制定的字符集解碼字節數組
byte [] getBytes(String charseName):使用指定的字符集合把字符串編碼爲字節數組。
String s="你好";
byte [] bys1=s.getBytes("GBK");
byte [] bys2=s.getBytes();
byte [] bys3=s.getBytes("UTF-8");
System.out.println(Arrays.toString(bys))//打印數組
String s1=new String(bys1);
String s2=new String(by2."GBK");
String s3=new String(by3,"UTF-8");
System.out.println(s1);
由於我們使用的是默認的簡體中文系統,因此默認使用的是GBK編碼表。當我們默認,或者指定將一串中文字符串轉爲byte數組時,我們看到的是兩個byte值的負數表示一個漢字字符。當我們指定用UTF-8編碼表時,我們看到的就會是三個byte值的負數表示一個漢字字符。
2、轉換流:
(1)、轉換輸出流的構造方法:
OutputStreamWriter(OutputStream out)//參數爲字節流
OutputStreamWriter(OutputStream out,String charsetName)//參數爲字節流加上指定編碼表
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.IOException;
class OutputStreamWriter{
public static void main(String [] args)throws IOException {
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("a.txt"));
OutputStreamWriter osw1=new OutputStreamWriter(new FileOutputStream("a.txt"),"UTF-8");//這裏由於是UTF-8的編碼,因此文本打開的時候,也需要選擇UTF-8.
osw.write("黑馬");
osw1.write("北京");
osw.close();
osw1.close();
}
}
(2)、轉換輸入流的構造方法:
InputStreamReader(InputStream in)//參數爲字節流
InputStreamReader(InputStream in,String charsetName)//參數爲字節流和編碼表
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.IOException;
class InputStreamReaderDemo{
public static void main(String [] args)throws IOException{
//這裏也可以採用參數爲字節流加上指定編碼表。
InputStreamReader isr=InputStreamReader(new FileInputStream("b.txt"));
int ch=0;
while((ch=isr.read())!=-1){
System.out.println((char)ch);
}
isr.close();
}
}
(3)、OutputStreamWriter的常用方法方法:
1、public void write(int c)//寫一個字符
2、public void write(char [] cbuf)//寫一個字符數組
3、public void write(char[] cbuf,int off,int len)//寫一個字符數組的一部分
4、public void write(String str)//寫一個字符串
5、public void write(String str,int off,int len)//寫一個字符串的一部分
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
class Demo{
public static void main(String [] args)throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("c.txt"));
osw.write('中');//write(int c);
osw.write("中國");//write(String str);
osw.flush();//刷新。一個字符等於兩個字節。
char [] chs={'a','b','c'};
osw.write(chs);
osw.close();
}
}
close()和flush()區別
close():關閉流對象,但是先刷新一次緩衝區。關閉之後,流對象不可以繼續再使用了。
flush():僅僅刷新緩衝區,刷新之後,流對象還可以繼續使用。
(4)、InputStreamReader的常用方法:
int read():一次讀取一個字符
int read(char [] chs):一次讀取一個字符數組
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileInputStream;
class InputStreamReaderDemo{
public static void main(String [] args)throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("d.txt"));
int len=0;//一次讀取一個字節
while((len=isr.read())!=-1){
System.out.print(char(len));
}
isr.close();
}<span style="white-space:pre"> </span>//一次讀取一個數組
/*InputStreamReader isr1=new InputStreamReader(new FileInputStream("e.txt"));
char [] chs=new char[1024];
int le=0;
while((le=isr1.read(chs))!=-1){
System.out.print(new String(chs,0,le));
}
isr.close();*/
}
3、字符流讀寫案例:
(1)、一次讀取一個字符複製
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
class CopyDemo{
public static void main(String [] args)throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("f.txt"));
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("g.txt"));
int ch=0;
//一次讀一個字符,直到返回爲-1
while((ch=isr.read())!=-1){
osw.write(ch);
}
//關閉轉換流
osw.close();
isr.close();
}
}
(2)、一次讀取一個字符數組複製
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
class CopyDemo1{
public static void main(String [] args)throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("h.txt");
InputStreamReader isr=new InputStreamReader(new FileInputStream("i.txt");
//定義一個字符數組的長度
char[] chs=new char[1024];
int len=0;
//一次讀一個字符數組的長度,直到長度爲-1
while((len=isr.read(chs))!=-1){
osw.write(chs,0,len);
}
//關閉轉換流
isr.close();
osw.close();
}
}
4、轉換流的簡化形式
由於我們使用本地編碼表,不使用制定編碼,又由於轉換流名字較長,因此就有了轉換流的子類
OutputStreamWriter=FileOutputStream+編碼表
FileWriter = FileOutStream+編碼表
InputStreamReader= FileInputStream+編碼表
FileReader =FileInputStream + 編碼表
一次讀取一個字符
import java.io.IOException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
class CopyDemo3{
public static void main(String [] args)throws IOException{
FileReader fr=new FileReader("j.txt");
FileWriter fw=new FileWriter("k.txt");
int ch=0;
while((ch=fr.read())!=-1){
fw.write(ch);
}
fr.close();
fw.close();
}
}
一次讀取一個字符數組
import java.io.IOException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
class CopyDemo4{
public static void main(String [] args)throws IOException{
FileReader fr=new FileReader("l.txt");
FileWriter fw=new FileWriter("m.txt");
char [] chs = new char[1024];
int len=0;
while((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
fw.flush();
}
fr.close();
fw.close();
}
}
5、高級字符緩衝流
BufferedWriter(Writer out)
字符緩衝輸出流構造函數.其參數爲字符轉換流。字符轉換流構造函數的的參數爲字節流。
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
class BufferedWriterDemo{
public static void main(String [] args)throws IOException{
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("n.txt")));
//上面的可以簡化爲:BufferedWriter bw=new BufferedWriter(new FileWriter("n.txt"));
bw.write("北京黑馬");
bw.close();
}
}
BufferedReader(Reader in)
字符緩衝輸入流
一次讀取一個字符
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
class BufferedReaderDemo{
public static void main(String [] args)throws IOException{
BufferedReader br=new BufferedReader(new FileReader("o.txt"));
int ch=0;
while((ch=br.read())!=-1){
System.out.print(char(ch));
}
br.close();
}
}
一次讀取一個字符數組
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
class BufferedReaderDemo{
public static void main(String [] args)throws IOException{
BufferedReader br=new BufferedReader(new FileReader("o.txt"));
char [] chs =new char[1024];
int len=0;
while((len=br.read(chs))!=-1){
System.out.print(new String(chs,0,len));
}
br.close();
}
}
用緩衝流複製文件:
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.bufferedWriter;
import java.io.FileWriter;
//一次讀取一個字符數組複製文件
class BufferedCopyDemo{
public static void main(String [] args)throws Exception{
BufferedReader br=new BufferedReader(new FileReader("p.txt"));
bufferedWriter bw=new BufferedWriter(new FileWriter("q.txt"));
char [] chs=new char[1024];
int len=0;
while((len=br.read(chs))!=-1){
bw.write(chs,0,len);
}
bw.close();
br.close();
}
}
一次讀取一個字符複製文件
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.bufferedWriter;
import java.io.FileWriter;
class BufferedCopyDemo{
public static void main(String [] args)throws Exception{
BufferedReader br=new BufferedReader(new FileReader("p.txt"));
bufferedWriter bw=new BufferedWriter(new FileWriter("q.txt"));
int ch=0;
while((ch=br.read())!=-1){
bw.write(ch);
}
bw.close();
br.close();
}
}
6、字符緩衝流的特殊方法:
BufferedWriter: public void newLine():根據系統來決定換行符
BufferedReader: public String readLine():一次讀取一行.包含了改行的字符串內容,不包含終止符。如果讀不到,返回null。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
class BufferedSpecialDemo{
public static void main(String [] args){
BufferedWriter bw =new BufferedWriter(new FileWriter("r.txt"));
for(int x=0;x<10;x++){
bw.write("黑馬"+x);
//起到換行效果
bw.write("\r\n");
//也起到換行效果
bw.newLine();
}
bw.close();
}
public static void read() throws IOException{
BufferedReader br=new BufferedReader(new FileReader("s.txt"));
String line=null;
while( (line=br.readLine()!=null){
System.out.println(line);
}
br.close();
}
}
特殊功能複製文件:一次讀一行
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.FileReader;
class ReaderLineCopy{
public static void main(String [] args) throws IOException{
BufferedReader br=new BufferedReader(new FileReader("t.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("u.txt"));
String line=null;
while((line=br.readLine())!=null){//一次讀取一行
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
第二部分:練習題:
1、將ArrayList集合中的字符串數據存儲到文本文件
分析:首先我們應該考慮到將數據存儲到文本,這個數據是從哪裏來的?毫無疑問,數據是從ArrayList集合中遍歷得到的,那麼我們遍歷得到的數據,該如何存儲到文本文件呢?方式有很多有字節流,也有字符流,這裏由於是文本文件,因此我們選擇的是字符流。在遍歷集合的過程中,將獲得的每一個集合元素,寫到文本中。
import java.io.IOException;
import java.util.ArrayList;
import java.io.FileWriter;
import java.io.BufferedWriter;
class ArrayListDemo{
public static void main(String [] args)throws IOException{
//創建一個ArrayList集合
ArrayList<String> list= new ArrayList<String>();
//創建一個字符緩衝流
BufferedWriter bw=new BufferedWriter(new FileWriter("v.txt"));
//爲集合添加數據
list.add("hello");
list.add("heima");
list.add("beijing");
//遍歷集合
for(String s:list){
//將遍歷獲得的集合元素,寫到文本中
bw.write(s);
bw.newLine();
bw.flush();
}
//關閉字符緩衝流
bw.close();
}
}
2、從文本文件中讀取數據(每一行爲一個字符串數據)到集合中,並遍歷集合
分析:數據是我們從文本文件中獲得的,這就要用到字符流或者字節流,這裏我們選擇了字符緩衝流來讀取文件數據,由於要求每一行爲一個字符串,因此我們選擇的是字符緩衝流中的readLine().在我們每讀一行時,通過集合的add方法,將改行的數據添加到集合。然後遍歷該集合,就能得到答案。
import java.io.IOException;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.FileReader;
class ReadText{
public static void main(String [] args)throws IOException{
//創建字符緩衝流
BufferedReader br=new BufferedReader(new FileReader("w.txt"));
//創建集合
ArrayList<String> list=new ArrayList<String>();
//定義一個String類型的變量
String line=null;
//調用字符緩衝流的特有方法readLine()來讀取數據
while((line=br.readLine())!=null){
//添加數據到集合
list.add(line);
}
//關閉字符緩衝流
br.close();
//遍歷集合
for(String s:list){
System.out.println(s);
}
}
}
3、複製單級文件夾
第一步:複製單級文件夾的時,首先先不考慮裏面的文件,而是考慮需要複製到的盤符裏是否有該文件夾,如果有,則不用創建,如果沒有,則要另外創建。
第二步:將需要複製的文件夾中的文件一一遍歷出來,由於是單級目錄,所以文件夾下都是文件,所以遍歷出來一個,就可以通過複製方法,將其複製到目標文件夾一個。
第三步:但是在複製之前,就是雖然目標文件夾我們在第一步就已經創建或者已經有了,但是我們知道在使用複製功能時,需要傳遞的是如同d:\\t.txt;e:\\y.txt這樣的文件路徑名,但是我們的目標文件地只有文件夾,還沒有文件名的全路徑,因此需要通過File的另一個構造函數:FIle file =new File(File file,String name);這裏面的參數前者是文件夾的路徑,後者是文件的文件名,因此這個封裝的就是文件全路徑名。這個時候就可以賦值了。這裏面的name可以再第二步的時候,通過getName()方法,從需要複製的文件身上得到。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputSteram;
class CopyFolder{
public static void main(String [] args)throws IOException{
File src=new File("d:\\x");//封裝源文件夾目錄
File dest=new File("e:\\y");//封裝目的地文件夾目錄
if(!dest.exists()){//如果目標文件夾不存在,就創建一個
dest.mkdir();
}
File [] fileArray=src.listFiles();//將源文件的每個對象封裝成一個對象
for(File file:fileArray){//得到每一個對象
String name=file.getName();//獲得每個對象的名字
File newFile=new File(dest,name);//創建目的地文件夾目錄對象
copy(file,newFile);//複製到目的地文件夾
}
}<span style="white-space:pre"> </span>//將複製方法封裝成獨立的方法
public static void copy(File file, File newFile)throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(newFile));
byte [] bys=new byte[1024];
int len=0;
while((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
}
4、複製單級文件夾中指定文件並修改文件後綴名
分析:這裏在複製的過程中,同上面一題的步驟相同,都是先封裝文件源目錄,和文件目的地目錄。如果文件目的地文件夾沒有就創建。
第二步是將源文件中需要複製的文件轉爲File[],這一步是通過文件過濾器來實現的。在上面那題複製文件夾時,我們不需要通過文件過濾器來選擇需要複製哪些文件,而是直接一窩端。文件過濾器可以將不需要複製的文件排除在外。這樣需要複製的文件就轉爲File [];
第三步,遍歷需要複製的文件數組,然後一個一個地複製到目標文件夾。
第四步,雖然複製到了目標文件夾,但是文件名沒有改,這時就可以再次將目標文件夾轉爲File[] 數組,遍歷獲得剛剛複製過來的文件。
第五步,再次遍歷這個File[]數組,裏面的每個剛剛複製過來的文件都是File類型,因此調用getName()可以得到該文件的名稱,獲取的這個名稱僅僅是個字符串,而不是這個文件本身,該文件的名稱是個字符串類型,因此可以通過字符串的替換功能,將需要改名後的名字替換先前的名字,現在這個字符串被替換成了我們需要的名字,但是如何才能把這個字符串重新賦給文件呢?這個時候可以通過File的構造函數File(File dir,String name);參數的前者是路徑,後者是文件名,這樣就相當建了一個新的File對象,新的文件名和複製過來後的路徑組合成了新的文件,然後再將舊的我們在這一步開始就遍歷獲得的那個文件名,也就是從源文件地複製過來的文件,更名爲新的File對象即可。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
class ModificationDemo{
public static void main(String [] args)throws IOException{
//封裝源文件夾目錄
File srcFile=new File("e:\\heima");
//封裝目的文件夾目錄
File destFile =new File("d:\\chuanzhi");
if(!destFile.exists()){
//如果沒有文件夾,將會建一個文件夾。但是destFile從始至終指向的都是d:\chuanzhi這個文件夾。儘管沒有這個文件夾,但是依然指向的是這個地方。這裏只是創建了這個文件夾而已。
destFile.mkdir();
}
//將需要複製的文件過濾出來,通過文件過濾器
File [] fileArray=srcFile.listFiles(new FilenameFilter(){
public boolean accept(File dir,String name){
return new File(dir,name).isFile()&&name.endsWith(".jpg");
}
});
//將需要複製的文件遍歷
for(File file:fileArray){
String name=file.getName();
File newFile=new File(destFile,name);
copy(file,newFile);
}
File[] destFileArray=destFile.listFiles();
for(File dest:destFileArray){
String name=dest.getName();
String newName=name.replace(".jpg",".jpeg");
File newFile =new File(destFile,newName);
dest.renameTo(newFile);
}
}
//封裝的複製方法
public static void copy(File file, File newFile)throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(newFile));
byte [] bys=new byte[1024];
int len=0;
while((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
}
5、複製多層文件夾
分析:複製多層文件夾,可以建兩個方法,一個方法時複製文件,一個方法時複製文件夾
在複製文件夾時,首先要封裝該文件夾,封裝後,通過該File的對象,來調用isDirectory()判斷,這個對象是文件還是文件夾。(1)如果是文件的話,就將目的地目錄和通過該文件對象調用的getName()作爲參數,來創建一個新File。這個新File就是目標文件所要複製到的地方。(2)如果對象是文件夾的話,通過文件夾對象來調用方法,獲得其名稱,然後和目標文件夾拼接成新的目的地文件夾。然後創建。這時再將對象轉成File類型的數組,通過遍歷該對象,就可以獲取對象文件夾下的內容,然後重複調用isDirectory()判斷是文件還是文件夾。
import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
class CopyFolderDemo{
public static void main(String [] args) throws IOException{
File srcFolder=new File("d:\\資料\\day03");
File destFolder=new File("e:\\");
copyFolder(srcFolder,destFolder);
}//複製文件夾的方法
public static void copyFolder(File srcFolder,File destFolder) throws IOException{
//判斷對象是不是文件夾
if(srcFolder.isDirectory()){
//如果是文件夾,就通過File的構造方法,將目的地和源文件夾名作爲參數,構造新的文件夾。
File newdestFolder=new File(destFolder,srcFolder.getName());
//在目的地創建該新的文件夾
newdestFolder.mkdir();
//將源文件夾對象的內容作爲對象,存入一個File類型的數組。
File[] fileArray=srcFolder.listFiles();
//遍歷該數組,得到的是該源文件夾內容的對象
for( File file:fileArray){
//重複複製文件夾,判斷其是文件夾還是文件。
copyFolder(file,newdestFolder);
}
}else{//如果是文件對象,就通過File的帶參構造方法,在目的文件夾中創建對象。其參數分別爲目的地文件夾路徑,源文件名稱。
File newFile=new File(destFolder,srcFolder.getName());
//複製該源文件
copy(srcFolder,newFile);
}
}
//複製文件的方法
public static void copy(File file, File newFile)throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(newFile));
byte [] bys=new byte[1024];
int len=0;
while((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
}