引出Properties
-
将一个媒体文件切割成多个碎片
1,切割文件的原理:一个源对应多个目的;切割文件的两种方式。
2,碎片文件的命名和编号。
3,程序代码体现。
4,如何记录源文件的类型以及碎片的个数(建立配置信息文件)(其实也可以将这些信息记录碎片文件中)
5,通过Properties属性集建立配置文件。
常见方法:load(InputStream) load(Reader)
store(OutputStream,conmments),store(Writer,conmments)
6,Properties的作为配置在应用程序很常见,主要用于将配置信息持久化。
建立的配置文件扩展名规范: .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 {
// 将一个媒体文件切割成多个碎片。
/*
* 思路:
* 1,读取源文件,将源文件的数据分别复制到多个文件中。
* 2,切割方式有两种:按照碎片个数切,要么按照指定大小切。
* 3,一个输入流对应多个输出流。
* 4,每一个碎片都需要编号,顺序不要错。
*
*/
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,使用字节流读取流和源文件关联。
FileInputStream fis = new FileInputStream(srcFile);
//2,明确目的。目的输出流有多个,只创建引用。
FileOutputStream fos = null;
//3,定义缓冲区。1M.
byte[] buf = new byte[BUFFER_SIZE];//1M
//4,频繁读写操作。
int len = 0;
int count = 1;//碎片文件的编号。
while((len=fis.read(buf))!=-1){
//创建输出流对象。只要满足了缓冲区大小,碎片数据确定,直接往碎片文件中写数据 。
//碎片文件存储到partsDir中,名称为编号+part扩展名。
fos = new FileOutputStream(new File(partsDir,(count++)+".part"));
//将缓冲区中的数据写入到碎片文件中。
fos.write(buf,0,len);
//直接关闭输出流。
fos.close();
}
/*
* 将源文件以及切割的一些信息也保存起来随着碎片文件一起发送。
* 信息;
* 1,源文件的名称(文件类型)
* 2,切割的碎片的个数。
* 将这些信息单独封装到一个文件中。
* 还要一个输出流完成此动作。
*/
String filename = srcFile.getName();
int partCount = count;
//创建一个输出流。
fos = new FileOutputStream(new File(partsDir,count+".properties"));
//创建一个属性集。
Properties prop = new Properties();
//将配置信息存储到属性集中。
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,它里面存储的键值都是字符串,通常这个集合就用于配置文件的操作
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 {
/*
* 配置文件规律,只要读取一行文本,按照 = 对文本进行切割即可。
*/
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]);
}
/*
* 发现配置文件信息很多,需要进行存储。
* 用哪个容器呢?个数不确定,就使用集合。
* 发现信息中存在对应关系,使用Map集合。
* 发现一点配置文件中的信息都是字符串,这些信息不在内存中而是在硬盘上。
* map中和io技术集合的集合对象: Properties,它里面存储的键值都是字符串,通常这个集合就用于配置文件的操作。
*
*/
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();
// 添加数据。
prop.setProperty("zhangsan", "39");
prop.setProperty("lisi", "29");
//想要把数据保存到文件中,需要输出流。
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方法,就可以将流中的数据加载集合中。原理;ReaderPartConfigDemo.java
// 中的readPathConfig();
prop.load(fr);
System.out.println(prop);
fr.close();
}
// 1,基本使用,存和取。
public static void methodDemo_1() {
// 创建一个Properites集合。
Properties prop = new Properties();
// 添加数据。
prop.setProperty("zhangsan", "39");
prop.setProperty("lisi", "29");
// 获取数据。一个。
// 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); //调试用
}
}
合并文件-序列流SequenceInputStream
1,文件合并的原理:多个源对应一个目的。
2,每一个碎片对应一个输入流,多个输入流对象先要进行集合存储。
3,SequenceInputStream可以解决这个问题。将多个源合并成一个源。
4,读取配置文件信息,并加入健壮性的判断。
5,独立解决碎片文件缺少的判断。
-
为什么需要序列流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,碎片文件有很多,每一个碎片都需要和读取流关联。 2,每一个读取流读取到的数据都需要通过一个输出流写入到一个文件中。
* 3,原理:多个源--->一个目的地。
*
*
* 如下代码的问题: 碎片过多,会产生很多的输入流对象,这是正常的,不正常在于,面对每一个输入流对象去操作。
* 当流对象过多时,必须先存储起来。面的流对象的容器操作更容易。 1,需要容器。 2,将流对象和碎片文件关联后存储到容器中。
* 3,遍历容器获取其中的流对象,在进行频繁的读写操作。 4,即使关流也是遍历容器对每一个流对象进行close的调用。
*/
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];
// 遍历集合,获取流对象。
for (FileInputStream fis : list) {
int len = fis.read(buf);
fos.write(buf, 0, len);
}
fos.close();
// 关闭所有流对象。
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 {
/*
* 虽然合并成功,问题如下:
* 1,如何明确碎片的个数,来确定循环的次数,以明确要有多少个输入流对象。
* 2,如何知道合并的文件的类型。
* 解决方案:应该先读取配置文件。
*/
//1,获取配置文件。
File configFile = getConfigFile(partsDir);
//2,获取配置文件信息容器。获取配置信息的属性集。
Properties prop = getProperties(configFile);
//3,将属性集对象传递合并方法中。
merge(partsDir,prop);
}
//根据配置文件获取配置信息属性集。
private static Properties getProperties(File configFile) throws IOException {
FileInputStream fis = null;
Properties prop = new Properties();
try{
//读取流和配置文件相关联。
fis = new FileInputStream(configFile);
//将流中的数据加载的集合中。
prop.load(fis);
}finally{
if(fis!=null){
try{
fis.close();
}catch(IOException e){
//写日志,记录异常信息。便于维护。
}
}
}
return prop;
}
//根据碎片目录获取配置文件对象。
private static File getConfigFile(File partsDir) {
if(!(partsDir.exists() &&partsDir.isDirectory())){
throw new RuntimeException(partsDir.toString()+",不是有效目录");
}
//1,判断碎片文件目录中是否存在properties文件。使用过滤器完成。
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扩展名的文件不存在,或不唯一");
}
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,对碎片文件进行合并,将多个读取流合并成一个读取流。
List<FileInputStream> list = new ArrayList<FileInputStream>();
for (int i = 1; i < partCount; i++) {
list.add(new FileInputStream(new File(partsDir, i + ".part")));
}
//怎么获取枚举对象呢?List自身是无法获取枚举Enumeration对象的,考虑到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();
}
}
应用练习
定义功能记录程序运行次数,满足试用次数后,给出提示:试用次数已到,请注册
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 {
/*
* 定义功能记录程序运行次数,满足试用次数后,给出提示:试用次数已到,请注册。
*
* 思路:
* 1,需要计数器。这个软件使用一次计数一次。每使用一次,就进行计数累计。
* 2,计数器是程序中的一个变量,程序启动计数器计数,可是程序结束这个计数器就消失了。
* 下次启动会重新进行计数,原来计数的值没有保留下来。咋办?
* 3,让这个计数器持久化。存储到文件中,为了标识数据可读性,数据起个名字。出现键值对。
* 而且还是一个持久化的键值对,Properties集合正好符合这个要求。
*
*/
if(isStop()){
System.out.println("试用次数已到,请注册");
return;
}
runcode();
}
private static boolean isStop() throws IOException {
//1,配置文件。
File configFile = new File("tempfile/app.properties");
if(!configFile.exists()){//如果配置文件不存在,就创建。
configFile.createNewFile();
}
//2,创建属性集。
Properties prop = new Properties();
//3,定义读取流和配置文件关联。
FileInputStream fis = new FileInputStream(configFile);
//4,将流关联的数据读取到属性集中。
prop.load(fis);
//5,通过属性集的指定键count,获取具体的次数。
String value = prop.getProperty("count");
int count = 0;
//6, 对value进行判断,如果存在就对其自增。
if(value!=null){
count = Integer.parseInt(value);
if(count>=5){
return true;
}
}
count++;//对其值进行自增。
//7,将自增后的值和指定的键重新存储到属性集中,键相同,值覆盖。
prop.setProperty("count", Integer.toString(count));
//8,将属性集存储到配置文件中。对配置文件中的信息进行更新。
FileOutputStream fos = new FileOutputStream(configFile);
prop.store(fos, "app run count");
//9,关闭资源。
fos.close();
fis.close();
return false;
}
//程序主体。
public static void runcode(){
System.out.println("程序运行....play");
}
}