Java基礎——IO流(三)

File類

  • 用來將文件或者文件夾封裝成對象
  • 方便對文件與文件夾的屬性信息進行操作
  • File對象可以作爲參數傳遞給流的構造函數
  • 瞭解File類的常用方法

創建文件對象


//創建一個文件對象的幾種方法
import java.io.*;
public class FileDemo {
    public static void main(String[] args) 
    {
        //通過絕對路徑創建對象
        File f1 = new File("E:\\others\\java\\day20file\\abc\\a.txt");
        sop("f1 = "+f1);
        //通過相對路徑創建對象
        File f2 = new File("b.txt");
        sop("f2 = "+f2);

        //指定父目錄,和子文件名稱
        File f3 = new File("E:\\others\\java\\day20file\\123","c.txt");
        sop("f3 = "+f3);

        //目錄通過引用的方法
        File d =  new File("E:\\others\\java\\day20file\\haha");
        File f4 = new File(d,"d.txt");
        sop("f4 = "+f4);
        //目錄可以引用,但是文件不可以引用

    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

創建文件對象

這裏邊的\分割符只適用於Windows系統,不是跨平臺的,

File.separator,與系統有關的默認名稱分隔符,爲了方便,它被表示爲一個字符串。

使用起來是這樣的。

File f = new File("E:"+File.separator+"others"+File.separator+"java"+File.separator+"day20file"+File.separator+"abc.txt");

File常見類的方法:

  1. 創建
    1. boolean createNewFile();在指定的位置創建文件,如果該文件已經存在,則不創建,返回false,和輸出流不一樣,輸出流對象一建立創建文件,而且文件已經存在,會覆蓋
    2. boolean mkdir();創建文件夾
    3. boolean mkdirs();創建多級文件夾
  2. 刪除
    1. boolean delete();刪除失敗,返回false
    2. void deleteOnExit();在程序退出時刪除指定文件
  3. 判斷
    1. boolean exists();文件是否存在。
    2. isFile();判斷文件對象是否是文件(該文件必須先 存在才返回真)
    3. isDirectory();判斷文件對象是否是路徑(文件夾)(該路徑必須先存在才返回真)
    4. isHidden();判斷文件是否隱藏
    5. isAbsolute();判斷路徑是否爲絕對路徑(該路徑可以不用存在)
  4. 獲取信息

簡單的方法操作演示。

//file類中的基本方法
import java.io.*;
public class FileDemo2 {
    //爲了演示看起來簡潔,先將異常拋出去
    public static void main(String[] args) throws IOException 
    {
        File f = new File("a.txt");//這是創建了一個對象,實際上什麼都沒有
        File f0 = new File("b.txt");

        //將該對象創建出來 實際的文件
        sop("a.txt文件是否創建成功?"+f.createNewFile());
        sop("b.txt文件是否創建成功?"+f0.createNewFile());

        //刪除文件
        //f0.deleteOnExit()//這是在虛擬機退出的時候刪除文件
        sop("文件b.txt刪除成功了嗎?"+f0.delete());//這是在代碼執行的時候刪除文件
        //創建一個路徑
        File f1 = new File("abcd");
        sop("abcd文件夾是否創建成功"+f1.mkdir());

        //創建多級目錄
        File f2 = new File("abc"+File.separator+"qq"+File.separator+"haha"+File.separator+"www");
        sop("“禮物是否準備好?”"+f2.mkdirs());

        //判斷文件是否存在?
        sop("a.txt文件是否存在呢?"+f.exists());
        sop("abcd文件夾是否存在呢?"+f1.exists());
        sop("abc文件夾是否存在呢?"+f2.exists());

        //判斷文件對象是文件還是文件夾
        sop("f是文件嗎?"+f.isFile());
        sop("f1是文件嗎?"+f1.isFile());
        sop("f2是文件嗎?"+f2.isFile());
        sop("f1是文件夾嗎?"+f1.isDirectory());
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

創建刪除判斷方法的演示

File對象中的獲取信息的方法

getName();獲取對象名稱
getPath();獲取相對路徑
getAbsolutePath();獲取絕對路徑
getParent();獲取對象的父目錄
long lastModified();獲取文件最後一次被修改的時間
long length();獲取文件的長度

//File類方法中的獲取方法類

import java.io.*;
public class FileDemo3 {
    public static void main(String[] args) 
    {
        File f1 = new File("abc\\a.txt");
        File f2 = new File("b.txt");

        //不創建實際文件也可以進行獲取
        sop(f1.getPath());//獲取相對路徑
        sop(f1.getAbsolutePath());//獲取絕對路徑
        sop(f2.getPath());

        sop(f1.getParent());//獲取父目錄
        sop(f2.getParent());

    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

獲取方法演示

這裏需要注意的是:

getParent方法,返回的是絕對路徑中的父目錄,如果獲取的是相對路徑,返回null
如果相對路徑中有上一層目錄,那麼該目錄就是返回結果。

替換文件名的方法演示:

//替換文件名稱的方法演示
import java.io.*;
public class FileDemo4 {
    public static void main(String[] args) throws IOException
    {
        File f1 = new File("E:\\others\\java\\day20file\\a.txt");
        File f2 = new File("E:\\others\\java\\day20file\\b.txt");

        f1.createNewFile();//將f1對象創建成存在的文件

        //將f1文件名替換成f2上的名稱
        sop("renameTo:"+f1.renameTo(f2));
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果爲:

第一次運行,打印結果爲真,第二次運行,打印結果爲假
文件名由a.txt變爲b.txt

File類中的其他方法演示:

static listRoots();//列出可用的文件系統根,也就是盤符

//File類中其他方法的演示
import java.io.*;
public class FileDemo4 {
    public static void main(String[] args) throws IOException
    {
        File[] files = File.listRoots();
        for(File f :files )
        {
            sop(f);
        }
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

獲取文件的系統根

list方法:返回一個字符串數組,這些字符串指定此路徑名錶示的目錄中的文件和目錄。

演示:

//列出指定目錄中所有的文件
import java.io.*;
public class FileDemo4 {
    public static void main(String[] args) throws IOException
    {
        //指定一個目錄名,這個目錄必須存在
        File f = new File("e:\\others\\java");
        //根據list方法獲取到目錄中的所有文件和文件夾的名稱
        String[] lists = f.list();
        for(String name:lists)
        {
            sop(name);
        }
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

list方法的用法

能不能獲取我想要的文件呢?比如說獲取後綴名爲.class的文件呢?

list方法的重載方法,可以做到,
在list方法的參數中傳一個FilenameFilter(接口)過濾器;然後複寫裏面的accept方法,

原理是:list方法可以獲取到該目錄下所有的文件,accept方法讀取到所有的文件名之後,進行條件的判斷,是不是以.class結尾的,如果是,則返回真,如果不是則返回假

//用過濾器選出想要的文件,並打印出來
import java.io.*;
public class FileDemo4 {
    public static void main(String[] args) throws IOException
    {
        //指定一個目錄名,這個目錄必須存在
        File f = new File("e:\\others\\java\\day20file");
        //根據list方法獲取到目錄中的所有文件和文件夾的名稱
        String[] lists = f.list(new FilenameFilter()//因爲FilenameFilter是一個接口,所以這裏用內部類的方法傳參數
        {
            //複寫裏邊的方法accept,參數爲一個file對象(目錄)一個String類型的文件名
            public boolean accept(File dir,String name)
            {
                return name.endsWith(".class");//只要list方法讀取到的文件的名稱的後綴名爲.class,就返回真
            }
        });
        for(String name:lists)//然後把集合中的內容打印出來
        {
            sop(name);
        }
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

這裏寫圖片描述

這個list方法可以獲取到的文件名,也就是字符串類型的,
listFiles方法可以獲取到文件對象File,可以進行更多的操作。

//用過濾器選出想要的文件對象,並打印出來獲取到的文件名和長度
import java.io.*;
public class FileDemo4 {
    public static void main(String[] args) throws IOException
    {
        File dir = new File("e:\\others\\java\\day20file");
        //使用listFiles方法獲取到所有的文件對象
        File[] files = dir.listFiles();
        for(File file:files)
        {
            sop(file.getName()+"....."+file.length());
        }
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

listFiles方法獲取所有的文件對象

發現,指定目錄下的文件夾的長度是獲取不到長度的,

那麼需求來了,,想要獲取到指定目錄中目錄中的文件,也就是目錄下還有目錄,需要將裏邊的所有文件打印出來。

因爲在目錄中還有目錄,只要使用同一個列出目錄功能的函數完成即可
在列出過程中出現還是目錄的話,還可以再次調用本功能
也就是函數自身調用自身
這種表現形式,或者變成手法,稱爲遞歸。

用代碼來演示遞歸:

//列出目錄中的所有文件,以及目錄中子目錄中的所有文件
import java.io.*;
public class AllFileList {
    public static void main(String[] args) 
    {
        File dir = new File("e:\\others\\java\\day20file");
        getDir(dir);//獲取目錄中文件的方法
    }
    public static void getDir(File dir)
    {
        sop(dir);//先打印一次目錄名
        File[] files = dir.listFiles();//獲取所有的文件對象
        for(File f:files)
        {
            if(f.isDirectory())//判斷如果獲取到的文件對象是目錄,就再調用一次自己的方法
                getDir(f);      //這種在自己的方法中再一次調用自己的方法的模式叫做遞歸
            sop(f.getName());//如果不是目錄就直接打印出來對象的名字
        }
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果:

獲取到路徑中的所有文件

使用遞歸時要注意
1,要有限定條件,否則就陷入了死循環
2,要注意遞歸的次數,儘量避免內存溢出。

演示幾個遞歸的例子:

public class DiGuiTest {
    public static void main(String[] args) 
    {
        toBin(6);//110;
        sop(getSum(10));//55
    }
    //獲取一個十進制數的二進制數
    public static void toBin(int num)
    {
        //判斷如果num值大於0.就調用一次自己的方法,然後再打印數據
        if (num>0)
        {
            toBin(num/2);
            sop(num%2);
        }
    }
    //獲取一個數從1加到他的總和
    public static int getSum(int n)
    {
        if(n==1)
            return 1;
        else
            return n+getSum(n-1);
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

再回來說之前打印目錄中的文件的例子,打印的很難看,沒有層次感,想在每一個目錄下邊加兩個空格,於是就要獲取到每個目錄的層次:

//列出目錄中的所有文件,以及目錄中子目錄中的所有文件
import java.io.*;
public class AllFileList {
    public static void main(String[] args) 
    {
        File dir = new File("e:\\others\\java\\day20file");
        getDir(dir,0);//獲取目錄中文件的方法
    }
    public static void getDir(File dir,int level)//該方法可以有層次的獲取目錄中的文件
    /*
    具體思路是,
    每調用一次該方法,level的值自增一次
    打印文件內容的時候,在前邊吧層次分割符加上,也就是加上getLevel方法就好了
    */
    {
        sop(getLevel(level)+dir.getPath());
        level++;
        File[] files = dir.listFiles();
        for(File f:files)
        {
            if(f.isDirectory())
                getDir(f,level);        
            sop(getLevel(level)+f.getName());
        }
    }
    public static String getLevel(int level)//該方法可以給每一個層次前邊添加空格,作爲層次分割符號
    /*
    具體思路是,在一個緩衝區中先加入一個|--符號,
    傳進來的數字是多少,就在該符號前邊添加多少個空格
    最後將字符串中的數據全部返回去
    */
    {
        StringBuilder sb = new StringBuilder();
        sb.append("|--");
        for(int x = 0;x<level;x++)
        {
            sb.insert(0,"  ");
        }
        return sb.toString();
    }
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
}

運行結果爲:

具有層次的獲取目錄中的文件

需求:刪除一個帶內容的目錄

刪除原理
在Windows中,刪除目錄是從裏面往外面刪除的,
既然是從裏往外刪除,就用到了遞歸。

//刪除目錄中的文件,連同目錄也刪了
import java.io.*;
public class DeleteDemo {
    public static void main(String[] args) 
    {
        File dir = new File ("e:\\others\\java\\day20file\\abcd");
        deleteDir(dir);
    }
    public static void deleteDir(File dir)
    {
        File[] files = dir.listFiles();
        for(File f : files)
        {
            if(f.isDirectory())
                deleteDir(f);//如果碰到目錄文件,再次調用自己的方法
            else
                f.delete();
        }
        //裏邊的東西都刪完了,該刪最外面的目錄了
        dir.delete();
    }
}

練習:將一個指定目錄下的java文件的絕對路徑,存儲到一個文本文件中
建立一個java文件列表文件

思路:
1,對指定的目錄進行遞歸
2,獲取遞歸過程所有的java文件的路徑
3,將這些路徑存儲到集合中

//將目錄中所有的java文件的絕對路徑存儲到一個txt文件中
import java.io.*;
import java.util.*;
public class JavaFileList {
    public static void main(String[] args) 
    {
        File dir = new File("e:\\others\\java");//指定一個目錄,要把這裏邊的所有java文件讀出來,
        List<File> list = new ArrayList<File> ();//按照思路,先把讀到的所有的文件對象存到集合中
        File file = new File(dir,"javafilelist.txt");//所有的數據要寫入的文件定義好
        getDir(dir,list);//該方法將dir目錄中的所有符合條件的文件對象裝進集合中
        listToText(list,file);//該方法將集合中的對象的絕對路徑值寫入到文件中
    }
    public static void getDir(File dir,List<File> list)
    {
        File[] files = dir.listFiles();
        for(File f : files)
        {
            if(f.isDirectory())
                getDir(f,list);
            else
            {
                if(f.getName().endsWith(".java"))//如果符合條件,將對象裝入到集合中
                    list.add(f);
            }
        }
    }
    public static void listToText(List<File> list,File file)//該方法將集合中的java文件對象的絕對路徑寫入到文件中
    {
        BufferedWriter bufw = null;
        try
        {
            bufw = new BufferedWriter(new FileWriter(file));
            for(File f1:list)
            {
                String path = f1.getAbsolutePath();
                bufw.write(path);
                bufw.newLine();
                bufw.flush();
            }

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if(bufw!=null)
                try
                {
                    bufw.close();               
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
        }
    }
}

運行結果:

最後生成的文件

Properties簡述

Properties是hashtable的子類
也就是說它具備map集合的特點,而且它裏邊存儲的鍵值都是字符串(不用定義泛型)

是集合中和IO技術相結合的集合容器

該對象的特點:可以用於鍵值對形式的配置文件

在加載數據時,通常有固定格式:鍵=值

比如:EditPlus中可以設置自己的字體顏色,當我設置以後把軟件關掉,重新開啓之後,字體顏色還是改過之後的,說明,我們改的屬性在軟件的配置文件中,軟件每次一運行,都會執行他的配置文件。

Properties的簡單操作:

//實現Properties的存取

import java.io.*;
import java.util.*;
public class PropertiesDemo {
    public static void main(String[] args) 
    {
        Properties prop = new Properties();//創建一個新的Properties對象
        set(prop);//在裏邊設置鍵值對
        modificatoin(prop);//修改裏邊的鍵值對
        get(prop);//獲取鍵值對
    }
    public static void set(Properties prop)//該方法用來設置裏邊的鍵值對
    {
        //使用setProperty();
        prop.setProperty("zhangsan","39");
        prop.setProperty("lisi","50");
        System.out.println(prop);
    }
    public static void modificatoin(Properties prop)//修改屬性鍵值對的內容
    {
        //還是用setProperty()方法
        prop.setProperty("lisi","88");
    }
    public static void get(Properties prop)//獲取屬性鍵值對中的信息
    {
        Set<String> names = prop.stringPropertyNames();//獲取到鍵的名稱,並存進set集合中
        for(String name:names)
        {
            System.out.println("name = "+name+".........."+"value = "+prop.get(name));
        }
    }
}

運行結果:

Properties方法演示

那麼如何將流中的數據存儲到集合中,
就是將info.txt中的數據加載進prop中?

//將流中的數據加載進集合
import java.io.*;
import java.util.*;
/*
思路是:
將一個文件和讀取流相關聯
將讀取到的整行的數據,用=分割開,作爲鍵和值
將分隔開的字符作爲鍵和值存儲金prop中
*/

//這裏爲了演示看起來方便,先將異常拋出,不予處理
public class FileToProp {
    public static void main(String[] args) throws IOException
    {
        method_2();
    }
    public static void method_1() throws IOException
    {
        //該方法是按照整體思路走的,可是實現將流中的數據存儲進prop中。
        BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
        Properties prop = new Properties();
        String line = null;
        while((line = bufr.readLine())!=null)
        {
            //讀取到的數據用=分割開
            String[] strs = line.split("=");
            //將=兩邊的數據分別加載進集合
            prop.setProperty(strs[0],strs[1]);
        }
        System.out.println(prop);
    }


    public static void method_2() throws IOException
    {
        //在Properties類中提供了將流中的數據加載進集合的方法load
        BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
        Properties prop = new Properties();
        prop.load(bufr);
        System.out.println(prop);
    }
}

運行結果:

將文件中的數據加載進集合

代碼中可以發現,使用Properties中的方法方便很多,

想到,如果我將數據加載進內存的時候,可不可以對數據進行修改呢?

//將流中的數據加載進集合
import java.io.*;
import java.util.*;
/*
思路是:
將一個文件和讀取流相關聯
將讀取到的整行的數據,用=分割開,作爲鍵和值
將分隔開的字符作爲鍵和值存儲金prop中
*/

//這裏爲了演示看起來方便,先將異常拋出,不予處理
public class FileToProp {
    public static void main(String[] args) throws IOException
    {
        method_2();
    }
    public static void method_1() throws IOException
    {
        //該方法是按照整體思路走的,可是實現將流中的數據存儲進prop中。
        BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
        Properties prop = new Properties();
        String line = null;
        while((line = bufr.readLine())!=null)
        {
            //讀取到的數據用=分割開
            String[] strs = line.split("=");
            //將=兩邊的數據分別加載進集合
            prop.setProperty(strs[0],strs[1]);
        }
        System.out.println(prop);
    }


    public static void method_2() throws IOException
    {
        //在Properties類中提供了將流中的數據加載進集合的方法load
        BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
        Properties prop = new Properties();
        //將流中的數據加載進內存
        prop.load(bufr);

        //在這裏對數據進行修改:
        prop.setProperty("lisi","3");

        //將集合中的元素輸出到指定的輸出流
        prop.list(System.out);
    }
}

運行結果發現,打印在控制檯上的數據,是修改之後的數據,但是原文件中的數據還是以前的,也就是說修改後的數據沒有保存在配置文件中。

prop.store方法,store(Writer writer, String comments)
將屬列表中的數據,寫入到輸出流中,comments是註釋,寫不寫都行的

對代碼進行修改:

//將流中的數據加載進集合
import java.io.*;
import java.util.*;


//這裏爲了演示看起來方便,先將異常拋出,不予處理
public class FileToProp {
    public static void main(String[] args) throws IOException
    {
        method_2();
    }


    public static void method_2() throws IOException
    {
        //在Properties類中提供了將流中的數據加載進集合的方法load
        FileInputStream fis = new FileInputStream("info.txt");
        Properties prop = new Properties();
        //將流中的數據加載進內存
        prop.load(fis);

        //在這裏對數據進行修改:
        prop.setProperty("lisi","39");

        //將集合中的元素輸出到指定的輸出流
        prop.list(System.out);

        //創建一個輸出流,和文件關聯
        FileOutputStream fos = new FileOutputStream("info.txt");
        //這裏注意,因爲這裏文件讀取流和文件寫入流關聯的是同一個文件,
        //不可以在相鄰的兩行中連續創建文件的讀取流和寫入流。

        //將列表中的文件再寫入到文件中
        prop.store(fos,"jaja");
        fis.close();
        fos.close();
    }
}

運行結果爲:

再將列表中的數據寫入到文件中

練習:建立一個配置文件,裏邊存儲軟件的運行次數,如果次數到了,那麼給出註冊提示。

思路:很容易想到的是計數器
可是該計數器定義在程序中,隨着程序的運行而在內存中存在並進行自增
可是隨着該應用程序的退出,該計數器也在內存中消失了

下一次再啓動程序,又從0開始計數。
這不是我們想要的,

程序即使結束,該計數器的值也存在
下次程序啓動會先加載該計數器的值,並加1後重新存儲起來

鍵值對數據是map集合
數據是以文件形式存數的,使用IO技術
那麼map+IO-->properties
//使用配置文件控制程序執行的次數
import java.io.*;
import java.util.*;
public class Runcount {
    public static void main(String[] args) throws IOException
    {
        File file = new File("count.ini");
        if(!file.exists())
            file.createNewFile();
        FileInputStream fis = new FileInputStream(file);
        Properties prop = new Properties();
        //每運行一次,先讀取配置文件中的額信息
        prop.load(fis);
        //找鍵爲time的值,第一次找是找不到的,返回null,count++後存進列表中
        //如果找到了,把count的值取出來自增後存進列表中
        String value = prop.getProperty("time");
        int count = 0;
        if(value!=null)
        {
            count = Integer.parseInt(value);
            if(count>=4)
                System.out.println("您好,您的試用次數已到,請您註冊");
        }
        count++;
        prop.setProperty("time",count+"");//Properties中的元素都是字符串,所以count+""表示將count轉換爲字符串
        //最後將雷彪中的信息寫進文件中。
        FileOutputStream fos = new FileOutputStream(file);
        prop.store(fos,"");
        fis.close();
        fos.close();
    }
}

運行結果爲:

設置配置文件的例子

打印流

該流提供了打印方法可以將各種數據類型的數據都原樣打印

字節打印流
PrintStream
構造函數可以接收的參數類型
1,file對象 File
2,字符串路徑 String
3,字節輸出流 OutputStream

字符打印流
PrintWriter
構造函數可以接收的參數類型
1,file對象 File
2,字符串路徑 String
3,字節輸出流 OutputStream
4,字符輸出流 Writer

簡單的演示一下,普通的獲取鍵盤錄入的數據,然後打印在控制檯上

//打印流的方法演示
//我想讀取鍵盤錄入,將鍵盤上敲的字符直接打印在控制檯上
import java.io.*;
public class PrintStreamDemo{
    public static void main(String[] args) throws IOException
    {
        //開啓兩個流對象,PrintWriter對象比Writer對象強大,
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(System.out);
        String line = null;
        while ((line = bufr.readLine())!=null)
        {
            if("over".equals(line))
                break;
            out.println(line.toUpperCase());//自帶換行的方法
            out.flush();//寫完要記得刷新,如果不刷新的話,他會將讀取到的數據寫入到緩衝區中
        }
        bufr.close();
        out.close();
    }
}

運行結果:
PrintWriter

PrintWriter的強大之處還在於,可以自己刷新

在構造方法時可以看到:
構造方法摘要

只有println方法輸出的時候,纔會用自己刷新的。只要在構造方法的時候,流參數後邊加一個true

//打印流的方法演示
//我想讀取鍵盤錄入,將鍵盤上敲的字符直接打印在控制檯上
import java.io.*;
public class PrintStreamDemo{
    public static void main(String[] args) throws IOException
    {
        //開啓兩個流對象,PrintWriter對象比Writer對象強大,
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(System.out,true);
        String line = null;
        while ((line = bufr.readLine())!=null)
        {
            if("over".equals(line))
                break;
            out.println(line.toUpperCase());//自帶換行的方法
            //上邊有了true,方法println會會自動刷新,這裏可以不用寫刷新方法
        }
        bufr.close();
        out.close();
    }
}

一樣可以運行的,
println方法自動刷新

那麼我想將鍵盤錄入的數據裝進一個文件裏呢?
只要將文件對象封裝成流對象就可以實現讀寫時候的自動刷新了。

//打印流的方法演示
//我想讀取鍵盤錄入,將鍵盤上敲的字符直接打印在一個文本文件中
import java.io.*;
public class PrintStreamDemo{
    public static void main(String[] args) throws IOException
    {
        //只要在這裏創建一個文件對象
        File file = new File("a.txt");
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        //在這裏將文件包裝成流對象,再傳入true值,就可以實現流的自動刷新。
        PrintWriter out = new PrintWriter(new FileWriter(file),true);
        String line = null;
        while ((line = bufr.readLine())!=null)
        {
            if("over".equals(line))
                break;
            out.println(line.toUpperCase());
        }
        bufr.close();
        out.close();
    }
}

運行結果:

鍵盤錄入數據

文件中寫入的文字

SequenceInputStream合併流對象

SequenceInputStream可以將多個流對象合併成一個大的流對象。
形成一個流對象的串聯模式。

比如:將三個文件中的數據要打印到同一個文件中,需要建立三個流對象,如果一個一個的往裏邊存的話,就麻煩了,所以這裏可以將三個流對象合併成一個大的流對象。

構造方法

構造方法可以看出來,有兩個流對象可以直接將流對象傳進去,
如果流對象多的話,直接用Enumeration集合中,(Enumeration集合是Vector接口中的子類)

示例如下:

//合併流演示
//將1.txt和2.txt和3.txt中的文字連續寫入到4.txt中
import java.io.*;
import java.util.*;
public class SequenceDemo {
    public static void main(String[] args) throws IOException
    {
        //先創建集合,將文件封裝成流對象存入集合中
        Vector<FileInputStream> v = new Vector<FileInputStream>();
        v.add(new FileInputStream("1.txt"));//文件中都是數字1
        v.add(new FileInputStream("2.txt"));//文件中都是數字2
        v.add(new FileInputStream("3.txt"));//文件中都是數字3
        //將集合中的元素用枚舉遍歷出來,交給一個對象en
        Enumeration<FileInputStream> en = v.elements();

        //萬事具備,創建大流
        SequenceInputStream sis = new SequenceInputStream(en);

        //創建目標文件的流對象
        FileOutputStream fos= new FileOutputStream(new File("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();
    }
}

運行結果爲:

SequenceInputStream

文件切割
將文件切割成相等的幾部分,
思路:
創建一個讀取流對象,和要切割的文件相關聯,
在創建一個寫入流的空引用,
開始讀取文件,創建一個固定大小的容器,讀到容器大小的數據就新創建一個寫入流對象,寫完立馬就把流關掉,
具體代碼演示:

//切割文件
import java.io.*;
import java.util.*;
public class SplitFile {
    public static void main(String[] args) 
    {
        File file = new File("1.mp3");
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try
        {
            //讀取流關聯文件
            fis = new FileInputStream(file);
            //固定緩衝區的長度爲1兆
            byte[] buf = new byte[1024*1024];
            int len = 0;
            int count = 1;
            while ((len = fis.read(buf))!=-1)
            {
                try
                {
                    //只要讀到了一兆的數據,馬上創建一個寫入流對象,將數據寫進去,寫完立馬關資源
                    fos = new FileOutputStream("e:\\others\\java\\day20file\\splitfile\\"+((count++)+".part"));             
                    fos.write(buf,0,len);
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    if(fos!=null)
                        fos.close();
                }
                //當再次讀夠一兆數據的時候,新開一個寫入流對象,寫入數據
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if(fis!=null)
                fis.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
}

運行結果:

切割下的文件

那麼能切割就可以把碎片文件拼在一起:用的是SequenceINputStream的方法

//切割文件
import java.io.*;
import java.util.*;
public class SplitFile {
    public static void main(String[] args)
    {
        spiltFile();
        pinJie();
    }
    //該方法可以將碎片文件拼接在一起
    public static void pinJie()
    {
        //Vector效率低,所以這裏用ArrayList集合存數據
        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
        for (int x = 1;x<6 ;x++ )
        {
            try
            {
                al.add(new FileInputStream("splitfile\\"+x+".part"));           
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        //而SequenceInputStream需要的參數是Enumeration的,這裏就要將ArrayList中的數據用枚舉的方式取出來
        final Iterator<FileInputStream> it = al.iterator();
        //因爲Enumeration是一個接口,裏邊只有兩個方法,所以可以給他創建子類對象,只要覆蓋兩個方法就可以了
        Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
        {
            public boolean hasMoreElements()
            {
                return it.hasNext();
            }
            public FileInputStream nextElement()
            {
                return it.next();
            }
        };
        //開始用SequenceInputStream獲取大流,寫數據
        SequenceInputStream sis = null;
        FileOutputStream fos  = null;
        try
        {
            sis = new SequenceInputStream(en);
            fos = new FileOutputStream(new File("splitfile\\2.mp3"));
            byte[] buf = new byte[1024];
            int len = 0;
            while((len = sis.read(buf))!=-1)
            {
                fos.write(buf,0,len);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if(sis!=null)
                try
                {       
                    sis.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            if(fos!=null)
            {
                try
                {
                    fos.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }

    }

    //該方法可以將文件切割開
    public static void spiltFile()
    {
        File file = new File("1.mp3");
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try
        {
            //讀取流關聯文件
            fis = new FileInputStream(file);
            //固定緩衝區的長度爲1兆
            byte[] buf = new byte[1024*1024];
            int len = 0;
            int count = 1;
            while ((len = fis.read(buf))!=-1)
            {
                try
                {
                    //只要讀到了一兆的數據,馬上創建一個寫入流對象,將數據寫進去,寫完立馬關資源
                    fos = new FileOutputStream("e:\\others\\java\\day20file\\splitfile\\"+((count++)+".part"));             
                    fos.write(buf,0,len);
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    if(fos!=null)
                        fos.close();
                }
                //當再次讀夠一兆數據的時候,新開一個寫入流對象,寫入數據
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if(fis!=null)
                fis.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
}

運行結果:

將文件碎片拼接在一塊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章