14.IO(三)【File】【Properties】【打印流PrintStream】【序列流SequenceInputStream】


一、File类

      1. 作用

          能将文件或者文件夹封装成对象,方便对文件或者文件夹的属性信息进行操作。

      2. File对象可以作为参数传递给流的构造函数。

 注意:创建对象时必须明确文件或者文件夹的名称。

            File.separator:名称分隔符

            Path.separator:路径分隔符。不同的系统,分隔符不一样,windows的分隔符是分号(;)。

      3. list()方法

          获取当前目录下的文件以及文件夹的名称,包含隐藏目录。

        调用list方法需要注意的事项:

        1)  调用list方法的File对象中封装的必须是目录,否则会发生java.lang.NullPointerException.。

        2)  如果访问的是系统级目录,也会发生空指针异常,需要加入健壮性判断。

        3)  如果目录存在但是没有内容,会返回一个数组,但是长度为0.

     4.File类常见方法     

       1)获取

            getName():获取文件名称

            getPath():获取文件路径

             length():获取文件大小

           lastModidied() :获取文件修改时间

          绝对路径:E:\eclipse\day22e\a.txt
         相对路径:a.txt
        没有盘符的,都是相对路径。

      2)创建与删除

          boolean createNewFile();创建文件
          boolean delete();删除
          boolean mkdir();创建单级目录
          boolean mkdirs();创建多级目录

      3)判断

       boolean canExecute();//是否是可执行文件

        boolean exists();//文件是否存在

        boolean isFile();//是否是文件

        boolean isDirectory();//是否是文件夹

        boolean isHidden();//是否是隐藏文件

        boolean isAbsolute();//文件是否是绝对路径

       注意:在判断文件对象是否是文件或者目录时,必须要判断该文件对象封装的内容是否存在。通过exists判断。

     4)重命名

        renameTo()

     5.  文件(文件名)过滤器

        原理:

        先用list()方法获取当前文件及文件夹名称,存储到数组,然后再遍历数组,符合FilenameFilter.accept(dir,name),返回的是 

        true,就把符合条件的存储起来。筛选后就是我们想要的。

     过滤器需要实现FilenameFilter接口,并重写accept(File dir, String name)方法。

    例子:list方法和过滤器的使用

   

<span style="font-size:18px">import io.p2.filter.FilterByHidden;
import io.p2.filter.FilterByJava;
import io.p2.filter.SuffixFilter;

import java.io.File;

public class FileListDemo {

	public static void main(String[] args) {

//		listDemo();
//		listDemo_2();
//		listDemo_3();
		
		listDemo_4();
	}
	
	public static void listDemo_4() {
		File dir = new File("E:\\eclipse\\day22e\\src\\io\\p1\\transstream\\demo");
		File[] names = dir.listFiles(new FilterByJava());
		for(File name : names){
			System.out.println(name);
		}
	}

	//File[] files = dir.listFiles()
	public static void listDemo_3() {
		File dir = new File("c:\\");
		File[] names = dir.listFiles(new FilterByHidden());
		for(File name : names){
			System.out.println(name);
		}
	}
	
	//使用过滤器,筛选出当前目录下以.java为后缀名的文件及文件夹
	public static void listDemo_2() {
		File dir = new File("E:\\eclipse\\day22e\\src\\io\\p1\\transstream\\demo");
		String[] files = dir.list(new FilterByJava());
		for(String file : files){
			System.out.println(file);
		}
	}
	// 获取 当前目录下的文件以及文件夹的名称,包含隐藏目录。
	public static void listDemo(){
		
		File file = new File("C:\\abcd");
				String[] names = file.list();
		System.out.println(names.length);
		
		for(String name : names){
			System.out.println(name);
		}
	}

}
</span>
<pre class="java" name="code"><span style="font-size:18px">import java.io.File;
import java.io.FilenameFilter;

public class FilterByJava implements FilenameFilter {

	@Override
	public boolean accept(File dir, String name) {
		//后缀名是.java的文件。
		return name.endsWith(".java");
	}
}</span>

//通用过滤器
 
<p><span style="font-size:18px">public class SuffixFilter implements FilenameFilter {</span></p><p><span style="font-size:18px"> private String Suffix;
 public SuffixFilter(String suffix) {
  super();
  this.Suffix = suffix;
 }
 @Override
 public boolean accept(File dir, String name) {
  return name.endsWith(Suffix);
 }
}</span></p>

 

    练习:获取指定目录下,指定拓展名的文件(包含子目录中的),这些文件的绝对路径写入到一个文本文件中。

    思路:
  1必须进行深度遍历。
  2.要在遍历过程中进行过滤,将符合条件的内容都存储到容器中。
  3.对容器中的内容进行遍历,并将绝对路径写入到文件中。

 

<span style="font-size:18px">public class Test {

	public static void main(String[] args) throws IOException {

		File dir = new File("E:\\eclipse\\day23e");
//		method(dir);
		
		//过滤器
		SuffixFilter filter = new SuffixFilter(".java");
		
		//存储符合过滤器条件的文件文件对象。
		List<File> list = new ArrayList<File>();
		
		getFiles(dir,filter,list);
		
		//目的文件
		File destFile = new File(dir,"javalist.txt");
		
		//写入文件
		writeToFile(list,destFile);
	}

	public static void writeToFile(List<File> list, File destFile) {
		BufferedWriter bufw = null;
				try {
					bufw = new BufferedWriter(new FileWriter(destFile));
					for(File file : list){
						bufw.write(file.getAbsolutePath());
						bufw.newLine();
						bufw.flush();
					}
				} catch (IOException e) {
					throw new RuntimeException("写入失败");
				}finally{
					if(bufw!=null)
						try {
							bufw.close();
						} catch (IOException e) {
							throw new RuntimeException("关闭失败");
						}
				}
				
		
	}

	/**
	 * 对指定目录的内容进行深度遍历,并按照指定过滤器进行过滤,
	 * 将过滤器后的内容存储到指定容器List中。
	 * @param dir
	 * @param filter
	 * @param list
	 */
	public static void getFiles(File dir, SuffixFilter filter, List<File> list) {
	
		File[] files = dir.listFiles();
		
		for (int i = 0; i < files.length; i++) {
			
			if(files[i].isDirectory()){
				//递归
				getFiles(files[i],filter,list);
			}
			
			else{
				//对遍历到的文件送到过滤器过滤,符合条件的File对象存储到list集合中。
				if(filter.accept(dir, files[i].getName())){
					list.add(files[i]);
				}
			}
		}
	
	}</span>


 

  6. 递归

    1. 概念

        函数自身直接或者间接的调用到自身。一个功能在被重复使用,并在使用时,每一次调用都与上一次结果有关。

    注意:

    1)  递归一定要明确条件,否则,递归只进不出,容易造成栈溢出

    2)  注意递归的次数。否则陷入死循环。

    2. 代码示例

publicclassDiGuiDemo {

publicstaticvoid main(String[] args) {

//      toBin(6);//结果为0 1 1

     System.out.println(getSum(10));//结果为55

}

publicstaticint getSum(int num) {

     if(num==1)

         return 1;

     return num+getSum(num-1);

}

//没有返回值的情况。

publicstaticvoid toBin(int num) {

     if(num>0){

         System.out.println(num%2);

         toBin(num/2);

     }

}

 

   递归练习1:对指定目录进行所有内容的列出(包含子目录中的内容),即深度遍历文件夹

 

<span style="font-size:18px">import java.io.File;
public class FileTest {
	public static void main(String[] args) {
		File file = new File("F:\\C语言");
		int level = 0;
		listAll(file,level);
	}

	public static void listAll(File file,int level) {
		System.out.println(getSpace(level)+file.getAbsolutePath());
		level++;
		File[] names = file.listFiles();
		for (int i = 0; i < names.length; i++) {

			if(names[i].isDirectory()){
				listAll(names[i],level);//自己调用自己,递归。
			}
			else
				System.out.println(names[i]);
		}
	}

	//缩进方法
	public static String getSpace(int level) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < level; i++) {
			sb.append("|--");
		}
		return sb.toString();
	}
}</span>

   

    练习2:  

    需求:删除一个带内容的目录
    原理:直接删除目录不行,目录里有内容。 必须从最里面往 外删除。所以需要深度遍历(递归)。

   

<span style="font-size:18px">import java.io.File;
public class RemoveDirTest {
	public static void main(String[] args) {
		File dir = new File("D:\\dirdemo");
		removeDir(dir);
	}

	public static void removeDir(File dir) {
		File[] files = dir.listFiles();
		for(File file : files){
			if(file.isDirectory()){
				removeDir(file);
			}
			else{
				System.out.println(file+":"+file.delete());
			}
			
			//删除文件后,将空的目录删除
			System.out.println(dir+":"+dir.delete());
		}
	}
}
</span>

 

二.Properties集合

1. 集合体系所属位置

  Map

    |--Hashtable

    |--Properties

2. Properties集合的特点

   1)  该集合中的键和值都是字符串类型。

   2)  集合中的数据可以保存到流中,或者从流中获取。

3. 什么时候使用Properties

    通常该集合用于操作以键值对形式存在的配置文件。

   配置文件:用于配置某些应用程序的文件。

   配置文件有一个很重要的特性就是持久化。将数据保存到硬盘,而不是保存到内存中,这样,断点之后,文件还存在。

4. 常用方法

   1)  存储和取出

        存:Object setProperty(String key,String value); 设置键和值,调用Hashtable的put方法

        取:String getProperty(String key);根据key获取对应的值。

   2)  加载和保存

      加载:void load(InputStreamism); 从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。 

      保存:voidstore(OutputStreamout,String comments); 对应load(InputStream )将属性列表(键值对)写入输出流。comments属

                性列表的描述。

   3)void list(PrintStream out);将属性列表输出到指定的输出流

 

<span style="font-size:18px">//load方法原理、
	public static void myLoad() throws IOException{
		test();
		Properties prop = new Properties();
		BufferedReader bufis = new BufferedReader(new FileReader("info.txt"));
		String line = null;
		while((line=bufis.readLine())!=null){
			if(line.startsWith("#")){//#开头的行不要。
				continue;
			}
			String[] subString = line.split("=");//细节:里面有信息提示,时间提示。这些不要。
			String key = subString[0];
			String value = subString[1];
			prop.setProperty(key, value);
		}
		prop.list(System.out);
		bufis.close();
	}
</span>


   Properties练习:获取一个应用程序运行的次数,如果超过5次,给出“使用次数已到,请注册”的提示。并不要再运行程序。

<span style="font-size:18px">import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

/* 
 *思路:
 *1.应该有计数器。
 *	每次程序启动都需要计数一次,并且是在原有的次数上进行计数!
 *2. 计数器是一个变量,程序启动时进行计数,计数器必须读取到内存中运算。(修改配置文件信息。)
 *	程序一结束,计数器就消失,那么再次启动该程序,计数器又重新被初始化。
 *	而我们需要多次启动同一个应用程序,使用的是同一个计数器。
 *	这就需要计数器的生命周期变长,从内存存储到硬盘中。
 *
 *3.如何使用这个计数器?
 *	首先,程序启动时,应该先读取这个用于记录计数器信息的配置文件。没有相应的配置文件时,应创建一个记录次数信息的文件。
 *	获取上一次计数器次数,并对次数进行判断,大于5的,程序停止运行,可以抛出RuntimeException异常。
 *	若小于5,对该次数进行自增,并将自增后的次数重新存储到配置文件中。
 *
 *4.文件中的信息该如何进行存储并体现?
 *	直接存储计数可以,但是不明确该数据的含义,所以应该给数据起名字。
 *	有了名字和值映射关系,使用键值对。
 *	可以存储映射关系的有Map集合。但又需要读取硬盘上的数据,Map+IO = Properties。
 */
public class PropertiesTest {
	public static void main(String[] args) throws IOException {
		getAppCount();
	}

	public static void getAppCount() throws IOException {
		//将配置文件封装成对象
		File confile = new File("count.properties");
		if(!confile.exists()){
			confile.createNewFile();
		}
		FileInputStream fis = new FileInputStream(confile);
		
		Properties prop = new Properties();
		prop.load(fis);
		
		//从集合中通过键获取次数。
		String value = prop.getProperty("time");
		
		//定义计数器,记录获取的次数
		int count = 0;
		if(value!=null){
			count = Integer.parseInt(value);
			if(count>=5){
				throw new RuntimeException("使用次数已到,请注册!");//抛出异常,程序停止。
			}
			count++;
		}
		
		//将修改后的值重新存储到集合中。
		prop.setProperty("time", count+"");
		FileOutputStream fos = new FileOutputStream("count.properties");
		//写入配置文件
		prop.store(fos, "");

		fos.close();
		fis.close();	
	}
}</span>

 


三、打印流

   1. PrintStream

    PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。PrintStream永远不会抛出IOException

    PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。

  其构造函数接收三种类型的值:

   1)字符串路径

   2)File对象

   3)字节流输出

代码示例

<span style="font-size:18px">import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;

public class PrintStreamDemo {
	public static void main(String[] args) throws IOException {

		PrintStream out = new PrintStream("print.txt");
		out.write(97);//只写最低8位。剩下的高24位忽略。
		out.print(97);//将97先变成字符串,保持原样,将数据打印到目的地。
		out.close();
	}

}
</span>

 

  2.  PrintWriter

     向文本输出流打印对象的格式化表示形式。

     如果启用了自动刷新,则只有在调用printlnprintfformat的其中一个方法时才可能完成此操作,而不是每当正好输出换行符

     时才完成。

    其构造函数接收四种类型的值:

       1)字符串路径

       2)File对象

       3)字节流输出

       4)字符流输出

代码示例

<span style="font-size:18px">import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class PrintWriterDemo {
	public static void main(String[] args) throws IOException {
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(System.out,true);//添加自动刷新
		
		//如果想写入到文件,并能自动刷新,可以将目的地封装成流对象。因为流对象带有自动刷新。
		//PrintWriter out1 = new PrintWriter(new FileWriter("out,txt"),true);//添加自动刷新
		String line = null;
		while((line=bufr.readLine())!=null){
			//添加控制台结束标志
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());
//			out.flush();
		}
		out.close();
		bufr.close();
	}
}
</span>

四、序列流SequenceInputStream

   1.  概念.

   SequenceInputStream可以实现合并多个文件,又称为合并流。

   2.  常用构造函数

       SequenceInputStream(Enumeration<?extendsFileInputStream> e)

   3.  使用序列流合并多个流文件的一般步骤

       1) 创建集合,并将流对象添加进集合

       2) 创建Enumeration对象,将集合元素加入

      3) 创建SequenceInputStream对象,合并流对象

      4) 创建写入流对象,FileOutputStream关联写入文件

      5) 利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作

练习:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中。

 方法1

 

<span style="font-size:18px">import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;

public class SequenceInputStreamDemo {

	public static void main(String[] args) throws IOException {
		
		/*
		 * 需求:将1.txt  2.txt  3.txt文件中的数据合并到一个文件中。
		 */
		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("123.txt");
		
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=sis.read(buf))!=-1){
			fos.write(buf,0,len);
		}
		
		fos.close();
		sis.close();
	}

}
</span>


方法二

 

<span style="font-size:18px">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.Iterator;

public class SequenceInputStreamDemo1 {

	public static void main(String[] args) throws IOException {
		
		/*
		 * 需求:将1.txt  2.txt  3.txt文件中的数据合并到一个文件中。
		 */

		//不用Vector,用ArrayList
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for (int i = 1; i <4; i++) {
			al.add(new FileInputStream(i+".txt"));
		}
		
		//没有枚举,可以自己造。也可以查找工具类Collections和Arrays
		Enumeration<FileInputStream> en = Collections.enumeration(al);
		SequenceInputStream sis = new SequenceInputStream(en);
		FileOutputStream fos = new FileOutputStream("12345.txt");
		
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=sis.read(buf))!=-1){
			fos.write(buf,0,len);
		}
		
		fos.close();
		sis.close();
	}

}</span>

 

练习二:文件切割器

<span style="font-size:18px">import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

/*
 * 文件切割器。
 * 
 * 
 * 思路:
 * 1.用读取流关联要切割的文件。定义碎片文件大小到缓冲字节数组。
 * 	用Properties集合存储文件拓展名。切割成多少个碎片。方便合并。
 * 2.按照文件大小来切割,创建碎片文件输出流,每次切割数据,就写入文件。关闭此次流文件。
 * 	若没到结尾,继续切割,创建新的碎片文件,存储数据。
 * 
 */
public class SplitFileDemo {

	private static final int SIZE = 10240;// 不要写两个数相乘,这样计算机还要运算

	public static void main(String[] args) throws IOException {
		File dir = new File("E:\\eclipse\\day23e");

		File file = new File(dir, "0.png");

		splitFile_2(file);

	}

	public static void splitFile_2(File file) throws IOException {

		// 用读取流关联源文件。
		FileInputStream fis = new FileInputStream(file);

		FileOutputStream fos = null;
		// 按照指定文件大小来切割。
		byte[] buf = new byte[SIZE];// 按照文件大小切割文件。

		int len = 0;
		int count = 1;

		/*
		 * 切割文件时,必须记录被切割文件的名称,以及切割出来碎片文件的个数,便于合并。
		 */

		// 创建Properties集合,存储文件信息。
		Properties prop = new Properties();

		File dir = new File("E:\\eclipse\\day24e\\partfile");
		if (!dir.exists())
			dir.mkdirs();

		while ((len = fis.read(buf)) != -1) {

			fos = new FileOutputStream(new File(dir, (count++) + ".part"));
			fos.write(buf, 0, len);
			fos.close();
		}

		// 将被切割的文件信息保存到prop集合中。
		prop.setProperty("partcount", count + "");
		prop.setProperty("filename", file.getName());

		fos = new FileOutputStream(new File(dir, count + ".properties"));

		// 将prop集合中的数据存储到文件中。
		prop.store(fos, "file save info");

		fos.close();
		fis.close();

	}

	public static void splitFile(File file) throws IOException {

		// 用读取流关联源文件。
		FileInputStream fis = new FileInputStream(file);

		FileOutputStream fos = null;
		// 按照指定文件大小来切割。
		byte[] buf = new byte[SIZE];

		int len = 0;
		int count = 1;

		File dir = new File("E:\\eclipse\\day24e\\partfile");
		if (!dir.exists())
			dir.mkdirs();

		while ((len = fis.read(buf)) != -1) {

			fos = new FileOutputStream(new File(dir, (count++) + ".part"));
			fos.write(buf, 0, len);
		}
		fos.close();
		fis.close();
	}
}
</span>


 


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

/*
 * 文件切割器。
 * 
 * 
 * 思路:
 * 1.用读取流关联要切割的文件。定义碎片文件大小到缓冲字节数组。
 * 	用Properties集合存储文件拓展名。切割成多少个碎片。方便合并。
 * 2.按照文件大小来切割,创建碎片文件输出流,每次切割数据,就写入文件。关闭此次流文件。
 * 	若没到结尾,继续切割,创建新的碎片文件,存储数据。
 * 
 */
public class SplitFileDemo {

	private static final int SIZE = 10240;// 不要写两个数相乘,这样计算机还要运算

	public static void main(String[] args) throws IOException {
		File dir = new File("E:\\eclipse\\day23e");

		File file = new File(dir, "0.png");

		splitFile_2(file);

	}

	public static void splitFile_2(File file) throws IOException {

		// 用读取流关联源文件。
		FileInputStream fis = new FileInputStream(file);

		FileOutputStream fos = null;
		// 按照指定文件大小来切割。
		byte[] buf = new byte[SIZE];// 按照文件大小切割文件。

		int len = 0;
		int count = 1;

		/*
		 * 切割文件时,必须记录被切割文件的名称,以及切割出来碎片文件的个数,便于合并。
		 */

		// 创建Properties集合,存储文件信息。
		Properties prop = new Properties();

		File dir = new File("E:\\eclipse\\day24e\\partfile");
		if (!dir.exists())
			dir.mkdirs();

		while ((len = fis.read(buf)) != -1) {

			fos = new FileOutputStream(new File(dir, (count++) + ".part"));
			fos.write(buf, 0, len);
			fos.close();
		}

		// 将被切割的文件信息保存到prop集合中。
		prop.setProperty("partcount", count + "");
		prop.setProperty("filename", file.getName());

		fos = new FileOutputStream(new File(dir, count + ".properties"));

		// 将prop集合中的数据存储到文件中。
		prop.store(fos, "file save info");

		fos.close();
		fis.close();

	}

	public static void splitFile(File file) throws IOException {

		// 用读取流关联源文件。
		FileInputStream fis = new FileInputStream(file);

		FileOutputStream fos = null;
		// 按照指定文件大小来切割。
		byte[] buf = new byte[SIZE];

		int len = 0;
		int count = 1;

		File dir = new File("E:\\eclipse\\day24e\\partfile");
		if (!dir.exists())
			dir.mkdirs();

		while ((len = fis.read(buf)) != -1) {

			fos = new FileOutputStream(new File(dir, (count++) + ".part"));
			fos.write(buf, 0, len);
		}
		fos.close();
		fis.close();
	}
}


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值