一、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
向文本输出流打印对象的格式化表示形式。
如果启用了自动刷新,则只有在调用println、printf或format的其中一个方法时才可能完成此操作,而不是每当正好输出换行符
时才完成。
其构造函数接收四种类型的值:
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();
}
}