------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
文件操作练习:
1,将指定目录的所有内容列出(深度遍历)
两个关键方法:list()和listFiles(),分别返回当前目录下的文件的字符串和对象。
如果对获取到的文件不进行操作,用list()即可,需要进一步操作用后者。
<pre name="code" class="html">import java.io.File;
public class FileListDemo {
public static void main(String[] args) {
// 关联指定目录
File dir = new File("f:\\视频");
// 创建方法遍历指定文件
listAll(dir,0);
System.out.println(getSum(10));
}
// 递归练习
private static int getSum(int num){
if(num==1)
return 1;
return num+getSum(num-1);
}
private static void listAll(File dir,int level) {
System.out.println(getSpace(level)+dir.getName());
level++;
// 获取指定目录下所有文件或文件夹的对象
File[] file = dir.listFiles();
// 遍历文件对象数组
for(int i=0; i<file.length; i++){
// 如果是文件夹,就继续遍历
if(file[i].isDirectory())
// 递归
/*
* 函数自身 直接或间接调用到了自身
* 什么时候用?一个功能在被重复使用,每次使用时,参与运算的结果和上一次调用有关
* 注意事项:1,递归一定要明确终止条件,否则容易栈溢出
* 2,注意递归的次数,过多也会导致栈溢出
*/
listAll(file[i],level);
else
System.out.println(getSpace(level)+file[i].getName());
}
}
// 未来修饰打印效果,为打印结果加上空格
private static String getSpace(int level) {
StringBuilder sb = new StringBuilder();
for(int x=0; x<level; x++){
sb.append(" ");
}
return sb.toString();
}
}
2,删除一个带内容的目录:
原理:必须从最面的文件开始向外删除,即需要进行深度遍历。
思路:遍历指定目录,从最深层文件开始向外依次删除。
import java.io.File;
public class RemoveFileDemo {
public static void main(String[] args) {
// 关联指定的目录
File dir = new File("F:\\a");
// 创建方法,删除指定目录
removeDir(dir);
}
private static void removeDir(File dir) {
File[] files = dir.listFiles();
// 遍历并删除文件
for(int i=0; i<files.length; i++){
// 如果是文件夹就继续遍历
if(files[i].isDirectory())
removeDir(files[i]);
else
files[i].delete();
}
// 每个目录下的文件删除后,将对应目录也删除
System.out.println(dir+":"+dir.delete());
}
}
3,Properties:Map集合下HashMap的一个子类,可以与IO技术相结合使用。
Properties集合特点:
a,集合中键和值都是字符串类型。
b,集合中的数据可以保存到流中,或者从流获取数据。
Properties用途:
该集合通常用来操作以键值对形式存在的配置文件。
Properties常用方法:setProperties(String key,String value)、getProperties(String key)、
Set<String> StringPropertyNames()
Properties与IO相结合可以用list(PrintStream out)方法,该方法用来输出,一般用于调试。
load(InputStream in)用于输入流与集合Properties建立联系
store(OutputStream out)用于输出流与集合Properties建立联系
方法演示:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
// 添加元素 注意:里面的键和值都是字符串
prop.setProperty("xiaoqiang", "27");
prop.setProperty("wangcai", "23");
prop.setProperty("wangwu", "33");
// method1(prop); // Properties基本操作
// method2(prop); // list方法演示
// method3(prop); // 持久化键值对
// method4(); // 将配置文件的内容读取到集合中
method5(); // 修改配置文件中的内容
}
private static void method5() throws IOException {
/*
* 思路:通过输入流读取配置文件的信息存储到Properties集合汇总,使用集合的修改方法修改,
* 完成后,将集合中的信息通过输出流持久化到文件中取
*/
// 读取文件,将指定文件包装成File类对象
File f = new File("info.txt");
if(!f.exists())
f.createNewFile();
FileReader fr = new FileReader(f);
// FileWriter fw = new FileWriter(f); 如果放到这,将会覆盖配置文件
// 创建集合存储配置文件中的信息
Properties prop = new Properties();
// 将流中的信息存储到prop中
prop.load(fr);
// 修改信息
prop.setProperty("wangwu", "155");
// 创建输出流,将修改后的信息存储到文件中
FileWriter fw = new FileWriter(f);
// 关联输出流
prop.store(fw,"java");
fw.close();
fr.close();
}
private static void method4() throws IOException {
/*
* 集合数据来源于一个配置文件,需要使用到输入流
* 因此需要建立输入流与properties集合与输入流之间的关系
*/
Properties prop = new Properties();
InputStream is = new FileInputStream("info.txt");
System.out.println(prop); // load之前集合为空
prop.load(is); // load 建立properties与输入流之间的关系
System.out.println(prop); // 之后将文件中的键值对存储到集合中了
}
private static void method3(Properties prop) throws IOException {
// 将prop中的键值对持久化存储到文件中,因此需要关联输出流
FileOutputStream fos = new FileOutputStream("info.txt");
// 用store(OutputStream out,String comment)来关联Properties和输出流
prop.store(fos, "java");
}
/**
* @param prop
*
*/
private static void method2(Properties prop) {
// 与IO相结合用list(PrintStream out) 主要用于调试
prop.list(System.out);
}
/**
* Properties基本操作
* @param prop
*/
private static void method1(Properties prop) {
// 修改
prop.setProperty("wangwu","22");
// 取一次
System.out.println(prop.getProperty("xiaoqiang"));
// 全部取出 使用stringPropertyNames
Set<String> names = prop.stringPropertyNames();
for(String name:names){
System.out.println(prop.getProperty(name));
}
}
}
4,Properties练习:获取一个应用程序的次数,如果超过5次,则给出”次数一到,请注册“的信息
思路:
a,创建计数器,每启动一次,在原有次数上+1
b,计数器是一变量,必须在内存中进行运算,运算结束计数器消失,怎么办?将计数器存于文件中
c,如何使用这个计数器?程序启动时,应先读取存储计数器的配置文件,获取上一次计数器的次数,用于判断,
然后进行自增运算,将新的计数器的次数存储到配置文件中
d,使用Properties和IO流读取/存储信息
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws IOException {
getAppCount();
}
private static void getAppCount() throws IOException {
// 将配置文件封装成File对象
File confile = new File("count.properties");
// 健壮性判断
if(!confile.exists())
confile.createNewFile();
// 创建输入流
FileInputStream fis = new FileInputStream(confile);
// 创建集合
Properties prop = new Properties();
prop.load(fis); // 将流中的数据存储到集合prop中
// 使用集合的方法,获取值
String value = prop.getProperty("time");
int count=0;
// 如果为空,说明程序没有启动过,如果不为空,则获取其使用过的次数,并与次数上限相比较处理
if(value!=null){
count = Integer.parseInt(value);<span style="white-space:pre"> </span>// 将string转成int
if(count>5)
throw new RuntimeException("次数已到,请注册!");
}
count++;
prop.setProperty("time", count+""); // 修改键值对
FileOutputStream fos = new FileOutputStream(confile);
prop.store(fos, "java"); // 将prop中的键值对写入配置信息
// 关闭流,释放资源
fos.close();
fis.close();
}
}
5,获取指定目录下,指定扩展名文件的路径
思路:深度遍历;遍历过程中进行过滤,使符合要求 的文件添加到集合中;对容器中的内容遍历并写入文件
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class IOTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 指定目录,并用File类进行封装
File dir = new File("E:\\数据\\BLS900");
// 创建过滤器,使用到了匿名内部类
FilenameFilter filter = new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".mnd");
}
};
List<File> list = new ArrayList<File>();
// 获取指定扩展名的绝对路径,并将路径存储到集合中
getFiles(dir,filter,list);
// 指定要写入的文件,并用File类进行封装
File file = new File("recorder.txt");
// 将集合中的数据写入文件
write2File(list,file);
}
private static void getFiles(File dir,FilenameFilter filter,List<File> list){
File[] files = dir.listFiles();
for(File file:files){
if(file.isDirectory()){
// 如果遍历到的文件时目录,继续调用getFiles方法--递归
getFiles(file,filter,list);
}else{
// 对遍历到的文件进行过滤(使用过滤器),讲符合条件的文件存储到集合中
// 注意过滤器的这种使用方法
if(filter.accept(dir, file.getName())){
list.add(file);
}
}
}
}
private static void write2File(List<File> list,File destFile) throws IOException{
BufferedWriter bufw = null;
try{
// 创建输出流,关联输出文件
bufw = new BufferedWriter(new FileWriter(destFile));
// 用到了高级for循环
for(File file:list){
bufw.write(file.getAbsolutePath());
bufw.newLine();
bufw.flush();
}
}finally{
if(bufw!=null){
try{
bufw.close();
}catch(IOException e){
}
}
}
}
}
6,PrintStream类 包括PrintStream和PrintWriter
PrintStream永远不会不抛IOException。如果打印对象都是文本数据的话,建议使用PrintWriter。
PrintStream提供了打印方法,可以对多种数据类型进行打印,并保持数据的表现形式。
构造函数包括:a,字符串路径 b,File对象 c,字节输出流
PrintWriter构造函数包括:a,字符串路径 b,File对象 c,字节输出流 d,字符输出流
演示代码:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
public class PrintDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// PrintStream
// show1();
// PrintWriter
show2();
}
/**
* @throws IOException
*/
private static void show2() throws IOException {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
// 构造参数 PrintWriter(OutputStream out,boolean autoFlush)
PrintWriter out = new PrintWriter(System.out,true);
// 将键盘输入内容直接打印到文件中,注意:应将文件封装到输出流中
// PrintWriter out = new PrintWriter(new FileWriter("autoprint.txt"),true);
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
// out.print(line); // 不换行
out.println(line);//换行
// out.flush(); // 如果不刷新,需要关闭时才刷新; 如果打印流的构造参数有自动刷新,则这句代码就不需要了
}
out.close();
bufr.close();
}
/**
* @throws FileNotFoundException
*/
private static void show1() throws FileNotFoundException {
// 用printStream关联文件,使用字符串路径形式
PrintStream out = new PrintStream("printdemo.txt");
out.write(610); //只写最低8位
out.print(97); // 将97先变成字符保持原样将数据打印到目的地
out.close();
}
}
7,序列流:对多个流进行排序。
SequenceInputStream
构造函数:SequenceInputSteram(Enumeration<? extends InputStream> e) 可以接收Enumeration,可以接收多个输入流
SequenceInputStream(InputStream s1,InputStream s2) 可以接收两个输入流
演示代码:
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.Vector;
public class SequenceInputStreamDemo {
public static void main(String[] args) throws IOException {
// 序列流形式1
// show1();
// 序列流形式2
show2();
}
private static void show2() throws IOException {
// ArrayList没有Enumeration,怎么办?可以自己创建,也可以去工具类中查找
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=1; x<=3; x++){
al.add(new FileInputStream(x+".txt"));
}
Enumeration<FileInputStream> en = Collections.enumeration(al);
// 下面这段代码,其实被封装了,Collections工具类提供了该方法
/*final Iterator<FileInputStream> it = al.iterator(); // 内部类访问局部变量时要加final
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
@Override
public boolean hasMoreElements() {
// TODO Auto-generated method stub
return it.hasNext();
}
@Override
public FileInputStream nextElement() {
// TODO Auto-generated method stub
return it.next();
}
};*/
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("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();
}
/**
* @throws FileNotFoundException
* @throws IOException
*/
private static void show1() throws FileNotFoundException, IOException {
// 创建vector集合,将输入流存入其中
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
// 创建迭代器对象
Enumeration<FileInputStream> en = v.elements();
// 将迭代器封装到序列流中
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("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();
}
}
8,练习:文件切割和合并
要点:文件切割时,需要将文件名称及碎片文件个数存储到配置信息中,以便后期合并
文件合并时,读取配置信息,可根据配置信息来确定碎片文件是否残缺等。
代码如下:
import java.io.File;
import java.io.FileInputStream;
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.Properties;
public class SplitFileDemo {
// BUFFER_SIZE大小为1M,不建议使用1024*1024,因为会多增加一次运算
private static final int BUFFER_SIZE = 1024*512 ;
public static void main(String[] args) throws IOException {
// 切割一张图片
File f = new File("a.jpg");
// 切割文件
splitFile(f);
// 合并文件
File dir = new File("D:\\JAVA\\Blog\\aaa");
// mergeFile(dir);
mergeFile2(dir);
}
private static void splitFile(File file) throws IOException {
// TODO Auto-generated method stub
/*
* 切割文件时,必须记录被切割文件的名称,以及切割出来的碎片文件的个数,便于合并
* 用键值对来记录这些信息,用到了Properties对象
*
*/
FileInputStream fis = new FileInputStream(file);
// 定义一个1M的缓冲区
byte[] buf = new byte[BUFFER_SIZE];
// 创建目的文件
FileOutputStream fos = null;
int len=0;
int count = 1;
// 将切割后的文件放到指定目录
File f = new File("D:\\JAVA\\Blog\\aaa");
// 如果文件夹不存在,就创建
if(!f.exists())
f.mkdirs();
while((len=fis.read(buf))!=-1){
// 将输出流关联目标文件
fos = new FileOutputStream(new File(f,(count++)+".part"));
fos.write(buf, 0, len);
// fos.close();
}
// 创建Properties集合
Properties prop = new Properties();
// 将被切割文件的信息存储到集合中
prop.setProperty("partcount", count+"");
prop.setProperty("filename",file.getName());
// 创建流关联存储被切割文件信息的文件
fos = new FileOutputStream(new File(f,count+".properties"));
// 将集合的数据持久化到文件中
prop.store(fos, "java");
// 关闭流,释放资源。
fos.close();
fis.close();
}
// 使用到配置信息的合并模式
private static void mergeFile2(File dir) throws IOException{
// 通过文件过滤器找到后缀名为properties的文件
File[] files = dir.listFiles(new SuffixFilter(".properties"));
// 健壮性判断
if(files.length!=1)
throw new RuntimeException();
// 记录配置文件对象
File confile = files[0];
// 读取配置文件信息
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(confile);
prop.load(fis);
// 获取文件名和碎片文件的个数
String fileName = prop.getProperty("filename");
int count = Integer.parseInt(prop.getProperty("partcount"));
// 获取碎片文件
File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
// 判断碎片文件数目与配置信息里记录的数目是否相同
if(partFiles.length!=(count-1))
throw new RuntimeException();
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
// 将输入流存放到集合中
for(int i=0; i<partFiles.length; i++){
al.add(new FileInputStream(partFiles[i]));
}
// 由工具类提供Enumeration
Enumeration<FileInputStream> en = Collections.enumeration(al);
// 将Enumeration作为序列流构造函数的参数进行传递
SequenceInputStream sis = new SequenceInputStream(en);
// 创建合并的目标文件并与输出流相关联
FileOutputStream fos = new FileOutputStream(new File(dir,fileName));
byte[] buf = new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1){
fos.write(buf, 0, len);
}
// 关闭流,释放资源
fos.close();
}
// 简单合并模式
private static void mergeFile(File dir) throws IOException{
/*
* 因为合并时通常会用到多个文件,因此就涉及到序列流
* 超过两个文件的序列流的构造参数中涉及到Enumeration,考虑到Vector低效,改用ArrayList
* 因为ArrayList没有Enumeration,因此有Collections类提供
*/
// 创建集合
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
// 将输入流存放到集合中
for(int i=1; i<=3; i++){
al.add(new FileInputStream(i+".part"));
}
// 由工具类提供Enumeration
Enumeration<FileInputStream> en = Collections.enumeration(al);
// 将Enumeration作为序列流构造函数的参数进行传递
SequenceInputStream sis = new SequenceInputStream(en);
// 创建合并的目标文件并与输出流相关联
FileOutputStream fos = new FileOutputStream(new File(dir,"merge.jpg"));
byte[] buf = new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1){
fos.write(buf, 0, len);
}
// 关闭流,释放资源
fos.close();
}
}