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常見類的方法:
- 創建
- boolean createNewFile();在指定的位置創建文件,如果該文件已經存在,則不創建,返回false,和輸出流不一樣,輸出流對象一建立創建文件,而且文件已經存在,會覆蓋
- boolean mkdir();創建文件夾
- boolean mkdirs();創建多級文件夾
- 刪除
- boolean delete();刪除失敗,返回false
- void deleteOnExit();在程序退出時刪除指定文件
- 判斷
- boolean exists();文件是否存在。
- isFile();判斷文件對象是否是文件(該文件必須先 存在才返回真)
- isDirectory();判斷文件對象是否是路徑(文件夾)(該路徑必須先存在才返回真)
- isHidden();判斷文件是否隱藏
- isAbsolute();判斷路徑是否爲絕對路徑(該路徑可以不用存在)
- 獲取信息
簡單的方法操作演示。
//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);
}
}
運行結果:
能不能獲取我想要的文件呢?比如說獲取後綴名爲.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);
}
}
運行結果:
發現,指定目錄下的文件夾的長度是獲取不到長度的,
那麼需求來了,,想要獲取到指定目錄中目錄中的文件,也就是目錄下還有目錄,需要將裏邊的所有文件打印出來。
因爲在目錄中還有目錄,只要使用同一個列出目錄功能的函數完成即可
在列出過程中出現還是目錄的話,還可以再次調用本功能
也就是函數自身調用自身
這種表現形式,或者變成手法,稱爲遞歸。
用代碼來演示遞歸:
//列出目錄中的所有文件,以及目錄中子目錄中的所有文件
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));
}
}
}
運行結果:
那麼如何將流中的數據存儲到集合中,
就是將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的強大之處還在於,可以自己刷新
在構造方法時可以看到:
只有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();
}
}
一樣可以運行的,
那麼我想將鍵盤錄入的數據裝進一個文件裏呢?
只要將文件對象封裝成流對象就可以實現讀寫時候的自動刷新了。
//打印流的方法演示
//我想讀取鍵盤錄入,將鍵盤上敲的字符直接打印在一個文本文件中
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();
}
}
運行結果爲:
文件切割
將文件切割成相等的幾部分,
思路:
創建一個讀取流對象,和要切割的文件相關聯,
在創建一個寫入流的空引用,
開始讀取文件,創建一個固定大小的容器,讀到容器大小的數據就新創建一個寫入流對象,寫完立馬就把流關掉,
具體代碼演示:
//切割文件
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();
}
}
}
}
運行結果: