引出Properties
-
將一個(gè)媒體文件切割成多個(gè)碎片
1,切割文件的原理:一個(gè)源對(duì)應(yīng)多個(gè)目的;切割文件的兩種方式。
2,碎片文件的命名和編號(hào)。
3,程序代碼體現(xiàn)。
4,如何記錄源文件的類型以及碎片的個(gè)數(shù)(建立配置信息文件)(其實(shí)也可以將這些信息記錄碎片文件中)
5,通過(guò)Properties屬性集建立配置文件。
常見方法:load(InputStream) load(Reader)
store(OutputStream,conmments),store(Writer,conmments)
6,Properties的作為配置在應(yīng)用程序很常見,主要用于將配置信息持久化。
建立的配置文件擴(kuò)展名規(guī)范: .properties。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class SplitFileTest {
private static final int BUFFER_SIZE = 1048576;//1024*1024
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 將一個(gè)媒體文件切割成多個(gè)碎片。
/*
* 思路:
* 1,讀取源文件,將源文件的數(shù)據(jù)分別復(fù)制到多個(gè)文件中。
* 2,切割方式有兩種:按照碎片個(gè)數(shù)切,要么按照指定大小切。
* 3,一個(gè)輸入流對(duì)應(yīng)多個(gè)輸出流。
* 4,每一個(gè)碎片都需要編號(hào),順序不要錯(cuò)。
*
*/
File srcFile = new File("1.mp3");
File partsDir = new File("PartFiles");
splitFile(srcFile,partsDir);
}
/**
* 切割文件。
* @param srcFile
* @param partsDir
* @throws IOException
*/
public static void splitFile(File srcFile, File partsDir) throws IOException {
//健壯性的判斷。
if(!(srcFile.exists() && srcFile.isFile())){
throw new RuntimeException("源文件不是正確的文件或者不存在");
}
if(!partsDir.exists()){
partsDir.mkdirs();
}
//1,使用字節(jié)流讀取流和源文件關(guān)聯(lián)。
FileInputStream fis = new FileInputStream(srcFile);
//2,明確目的。目的輸出流有多個(gè),只創(chuàng)建引用。
FileOutputStream fos = null;
//3,定義緩沖區(qū)。1M.
byte[] buf = new byte[BUFFER_SIZE];//1M
//4,頻繁讀寫操作。
int len = 0;
int count = 1;//碎片文件的編號(hào)。
while((len=fis.read(buf))!=-1){
//創(chuàng)建輸出流對(duì)象。只要滿足了緩沖區(qū)大小,碎片數(shù)據(jù)確定,直接往碎片文件中寫數(shù)據(jù) 。
//碎片文件存儲(chǔ)到partsDir中,名稱為編號(hào)+part擴(kuò)展名。
fos = new FileOutputStream(new File(partsDir,(count++)+".part"));
//將緩沖區(qū)中的數(shù)據(jù)寫入到碎片文件中。
fos.write(buf,0,len);
//直接關(guān)閉輸出流。
fos.close();
}
/*
* 將源文件以及切割的一些信息也保存起來(lái)隨著碎片文件一起發(fā)送。
* 信息;
* 1,源文件的名稱(文件類型)
* 2,切割的碎片的個(gè)數(shù)。
* 將這些信息單獨(dú)封裝到一個(gè)文件中。
* 還要一個(gè)輸出流完成此動(dòng)作。
*/
String filename = srcFile.getName();
int partCount = count;
//創(chuàng)建一個(gè)輸出流。
fos = new FileOutputStream(new File(partsDir,count+".properties"));
//創(chuàng)建一個(gè)屬性集。
Properties prop = new Properties();
//將配置信息存儲(chǔ)到屬性集中。
prop.setProperty("filename", srcFile.getName());
prop.setProperty("partcount", Integer.toString(partCount));
//將屬性集中的信息持久化。
prop.store(fos, "part file info");
// fos.write(("filename="+filename+LINE_SEPARATOR).getBytes());
// fos.write(("partcount="+Integer.toString(partCount)).getBytes());
fos.close();
fis.close();
}
}
-
配置文件的建立和讀取
Properties,它里面存儲(chǔ)的鍵值都是字符串,通常這個(gè)集合就用于配置文件的操作
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReaderPartConfigDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//解析partConfig文件中的信息。
File configFile = new File("PartFiles/7.partconfig");
readPathConfig(configFile);
}
public static void readPathConfig(File configFile) throws IOException {
/*
* 配置文件規(guī)律,只要讀取一行文本,按照 = 對(duì)文本進(jìn)行切割即可。
*/
BufferedReader bufr = new BufferedReader(new FileReader(configFile));
String line = null;
while((line=bufr.readLine())!=null){
String[] arr = line.split("=");
System.out.println(arr[0]+":::::"+arr[1]);
//map.put(arr[0],arr[1]);
}
/*
* 發(fā)現(xiàn)配置文件信息很多,需要進(jìn)行存儲(chǔ)。
* 用哪個(gè)容器呢?個(gè)數(shù)不確定,就使用集合。
* 發(fā)現(xiàn)信息中存在對(duì)應(yīng)關(guān)系,使用Map集合。
* 發(fā)現(xiàn)一點(diǎn)配置文件中的信息都是字符串,這些信息不在內(nèi)存中而是在硬盤上。
* map中和io技術(shù)集合的集合對(duì)象: Properties,它里面存儲(chǔ)的鍵值都是字符串,通常這個(gè)集合就用于配置文件的操作。
*
*/
bufr.close();
}
}
Properties詳解
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// Properties集合的使用。
// methodDemo_1();
// methodDemo_2();
methodDemo_3();
}
/*
* 保存到流中的方法(持久化)
*/
public static void methodDemo_3() throws IOException {
Properties prop = new Properties();
// 添加數(shù)據(jù)。
prop.setProperty("zhangsan", "39");
prop.setProperty("lisi", "29");
//想要把數(shù)據(jù)保存到文件中,需要輸出流。
FileWriter fw = new FileWriter("info.properties");
//使用store方法。
prop.store(fw, "info");
fw.close();
}
/*
* 演示從流中加載,。
*/
public static void methodDemo_2() throws IOException {
File configFile = new File("PartFiles/7.partconfig");
FileReader fr = new FileReader(configFile);
Properties prop = new Properties();
// 使用Properties集合的load方法,就可以將流中的數(shù)據(jù)加載集合中。原理;ReaderPartConfigDemo.java
// 中的readPathConfig();
prop.load(fr);
System.out.println(prop);
fr.close();
}
// 1,基本使用,存和取。
public static void methodDemo_1() {
// 創(chuàng)建一個(gè)Properites集合。
Properties prop = new Properties();
// 添加數(shù)據(jù)。
prop.setProperty("zhangsan", "39");
prop.setProperty("lisi", "29");
// 獲取數(shù)據(jù)。一個(gè)。
// String value = prop.getProperty("lisi");
// System.out.println("value="+value);
// 全部取出。map--set--iterator
Set<String> set = prop.stringPropertyNames();
// System.out.println("-- listing properties --");
for (String name : set) {
String value = prop.getProperty(name);
System.out.println(name + ":" + value);
}
// prop.list(System.out); //調(diào)試用
}
}
合并文件-序列流SequenceInputStream
1,文件合并的原理:多個(gè)源對(duì)應(yīng)一個(gè)目的。
2,每一個(gè)碎片對(duì)應(yīng)一個(gè)輸入流,多個(gè)輸入流對(duì)象先要進(jìn)行集合存儲(chǔ)。
3,SequenceInputStream可以解決這個(gè)問(wèn)題。將多個(gè)源合并成一個(gè)源。
4,讀取配置文件信息,并加入健壯性的判斷。
5,獨(dú)立解決碎片文件缺少的判斷。
-
為什么需要序列流SequenceInputStream
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MergeFileTest2 {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 合并碎片文件。
/*
* 思路: 1,碎片文件有很多,每一個(gè)碎片都需要和讀取流關(guān)聯(lián)。 2,每一個(gè)讀取流讀取到的數(shù)據(jù)都需要通過(guò)一個(gè)輸出流寫入到一個(gè)文件中。
* 3,原理:多個(gè)源--->一個(gè)目的地。
*
*
* 如下代碼的問(wèn)題: 碎片過(guò)多,會(huì)產(chǎn)生很多的輸入流對(duì)象,這是正常的,不正常在于,面對(duì)每一個(gè)輸入流對(duì)象去操作。
* 當(dāng)流對(duì)象過(guò)多時(shí),必須先存儲(chǔ)起來(lái)。面的流對(duì)象的容器操作更容易。 1,需要容器。 2,將流對(duì)象和碎片文件關(guān)聯(lián)后存儲(chǔ)到容器中。
* 3,遍歷容器獲取其中的流對(duì)象,在進(jìn)行頻繁的讀寫操作。 4,即使關(guān)流也是遍歷容器對(duì)每一個(gè)流對(duì)象進(jìn)行close的調(diào)用。
*/
List<FileInputStream> list = new ArrayList<FileInputStream>();
for (int i = 1; i < 7; i++) {
list.add(new FileInputStream("PartFiles/" + i + ".part"));
}
FileOutputStream fos = new FileOutputStream("PartFiles/00.mp3");
byte[] buf = new byte[1024 * 1024];
// 遍歷集合,獲取流對(duì)象。
for (FileInputStream fis : list) {
int len = fis.read(buf);
fos.write(buf, 0, len);
}
fos.close();
// 關(guān)閉所有流對(duì)象。
for (FileInputStream fis : list) {
fis.close();
}
}
}
-
使用序列流SequenceInputStream合并文件
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
public class MergerFileTest3 {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
File partsDir = new File("E:\\PartFiles");
mergerFile(partsDir);
}
public static void mergerFile(File partsDir) throws IOException {
/*
* 雖然合并成功,問(wèn)題如下:
* 1,如何明確碎片的個(gè)數(shù),來(lái)確定循環(huán)的次數(shù),以明確要有多少個(gè)輸入流對(duì)象。
* 2,如何知道合并的文件的類型。
* 解決方案:應(yīng)該先讀取配置文件。
*/
//1,獲取配置文件。
File configFile = getConfigFile(partsDir);
//2,獲取配置文件信息容器。獲取配置信息的屬性集。
Properties prop = getProperties(configFile);
//3,將屬性集對(duì)象傳遞合并方法中。
merge(partsDir,prop);
}
//根據(jù)配置文件獲取配置信息屬性集。
private static Properties getProperties(File configFile) throws IOException {
FileInputStream fis = null;
Properties prop = new Properties();
try{
//讀取流和配置文件相關(guān)聯(lián)。
fis = new FileInputStream(configFile);
//將流中的數(shù)據(jù)加載的集合中。
prop.load(fis);
}finally{
if(fis!=null){
try{
fis.close();
}catch(IOException e){
//寫日志,記錄異常信息。便于維護(hù)。
}
}
}
return prop;
}
//根據(jù)碎片目錄獲取配置文件對(duì)象。
private static File getConfigFile(File partsDir) {
if(!(partsDir.exists() &&partsDir.isDirectory())){
throw new RuntimeException(partsDir.toString()+",不是有效目錄");
}
//1,判斷碎片文件目錄中是否存在properties文件。使用過(guò)濾器完成。
File[] files = partsDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".properties");
}
});
if(files.length!=1){
throw new RuntimeException("properties擴(kuò)展名的文件不存在,或不唯一");
}
File configFile = files[0];
return configFile;
}
private static void merge(File partsDir,Properties prop) throws FileNotFoundException,
IOException {
//獲取屬性集中的信息。
String filename = prop.getProperty("filename");
int partCount = Integer.parseInt(prop.getProperty("partcount"));
//使用io包中的SequenceInputStream,對(duì)碎片文件進(jìn)行合并,將多個(gè)讀取流合并成一個(gè)讀取流。
List<FileInputStream> list = new ArrayList<FileInputStream>();
for (int i = 1; i < partCount; i++) {
list.add(new FileInputStream(new File(partsDir, i + ".part")));
}
//怎么獲取枚舉對(duì)象呢?List自身是無(wú)法獲取枚舉Enumeration對(duì)象的,考慮到Collections中去找。
Enumeration<FileInputStream> en = Collections.enumeration(list);
//源。
SequenceInputStream sis = new SequenceInputStream(en);
//目的。
FileOutputStream fos = new FileOutputStream(new File(partsDir,filename));
//不斷的讀寫。
byte[] buf = new byte[4096];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
應(yīng)用練習(xí)
定義功能記錄程序運(yùn)行次數(shù),滿足試用次數(shù)后,給出提示:試用次數(shù)已到,請(qǐng)注冊(cè)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class AppCountTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 定義功能記錄程序運(yùn)行次數(shù),滿足試用次數(shù)后,給出提示:試用次數(shù)已到,請(qǐng)注冊(cè)。
*
* 思路:
* 1,需要計(jì)數(shù)器。這個(gè)軟件使用一次計(jì)數(shù)一次。每使用一次,就進(jìn)行計(jì)數(shù)累計(jì)。
* 2,計(jì)數(shù)器是程序中的一個(gè)變量,程序啟動(dòng)計(jì)數(shù)器計(jì)數(shù),可是程序結(jié)束這個(gè)計(jì)數(shù)器就消失了。
* 下次啟動(dòng)會(huì)重新進(jìn)行計(jì)數(shù),原來(lái)計(jì)數(shù)的值沒(méi)有保留下來(lái)。咋辦?
* 3,讓這個(gè)計(jì)數(shù)器持久化。存儲(chǔ)到文件中,為了標(biāo)識(shí)數(shù)據(jù)可讀性,數(shù)據(jù)起個(gè)名字。出現(xiàn)鍵值對(duì)。
* 而且還是一個(gè)持久化的鍵值對(duì),Properties集合正好符合這個(gè)要求。
*
*/
if(isStop()){
System.out.println("試用次數(shù)已到,請(qǐng)注冊(cè)");
return;
}
runcode();
}
private static boolean isStop() throws IOException {
//1,配置文件。
File configFile = new File("tempfile/app.properties");
if(!configFile.exists()){//如果配置文件不存在,就創(chuàng)建。
configFile.createNewFile();
}
//2,創(chuàng)建屬性集。
Properties prop = new Properties();
//3,定義讀取流和配置文件關(guān)聯(lián)。
FileInputStream fis = new FileInputStream(configFile);
//4,將流關(guān)聯(lián)的數(shù)據(jù)讀取到屬性集中。
prop.load(fis);
//5,通過(guò)屬性集的指定鍵count,獲取具體的次數(shù)。
String value = prop.getProperty("count");
int count = 0;
//6, 對(duì)value進(jìn)行判斷,如果存在就對(duì)其自增。
if(value!=null){
count = Integer.parseInt(value);
if(count>=5){
return true;
}
}
count++;//對(duì)其值進(jìn)行自增。
//7,將自增后的值和指定的鍵重新存儲(chǔ)到屬性集中,鍵相同,值覆蓋。
prop.setProperty("count", Integer.toString(count));
//8,將屬性集存儲(chǔ)到配置文件中。對(duì)配置文件中的信息進(jìn)行更新。
FileOutputStream fos = new FileOutputStream(configFile);
prop.store(fos, "app run count");
//9,關(guān)閉資源。
fos.close();
fis.close();
return false;
}
//程序主體。
public static void runcode(){
System.out.println("程序運(yùn)行....play");
}
}