黑马程序员----JAVA基础----IO流_2

------<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();
	}
	
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值