一、概述
Apache Commons IO 是Apache Commons的组件,它们源自Java API并提供各种用于文件IO的常见操作的实用程序类,涵盖各种用例,可以大大简化我们处理io流和操作文件的代码。Java IO操作是开发中比较常用的技术,但是如果每次都使用原生的IO流来操作会显得比较繁琐。例如,普通地读取一个网页的源代码的代码可能如下:
InputStream in = new URL("http://commons.apache.org").openStream();
try {
InputStreamReader inR = new InputStreamReader(in);
BufferedReader buf = new BufferedReader(inR);
String line;
while ((line = buf.readLine()) != null) {
System.out.println(line);
}
} finally {
in.close();
}
使用了Commons IO,则可以大大简化代码,如下:
InputStream in = new URL("http://commons.apache.org").openStream();
try {
System.out.println(IOUtils.toString(in, "UTF-8"));
} finally {
IOUtils.close(in);
}
二、常用类
Apache Commons IO库提供以下类别的类
包 | 说明 |
---|---|
org.apache.commons.io | 有关streams、readers、writers、files等实体类以及工具类 |
org.apache.commons.io.comparator | 文件的比较、排序 |
org.apache.commons.io.filefilter | 基于逻辑标准过滤文件 |
org.apache.commons.io.input | 文件输入(InputStream、Reader)的实现 |
org.apache.commons.io.monitor | 文件跟踪及相关事件的监视器 |
org.apache.commons.io.output | 文件输出(OutputStream、Writer)的实现 |
org.apache.commons.io.serialization | 序列化 |
2.1 工具类
工具类包括FileUtils、IOUtils、FilenameUtils,这三者的方法可以说并没有太大的区别,只是操作的对象不同。顾名思义,FileUtils主要操作File类,IOUtils主要操作IO流,FilenameUtils则是操作文件名。
2.1.2 IOUtils
IOUtils 包含一些工具类,用于处理读、写和拷贝,这些方法适用于InputStream、OutputStream、Reader和Writer。
方法 | 说明 |
---|---|
BufferedInputStream buffer(InputStream inputStream) | 将传入的流进行包装,变成缓冲流。 并可以通过参数指定缓冲大小 |
close(Closeable closeable) | 关闭流 |
closeQuietly(Closeable closeable) | 关闭流 |
contentEquals(InputStream input1,InputStream input2) | 比较两个流中的内容是否相等 |
contentEqualsIgnoreEOL(Reader reader1,Reader reader2) | 比较两个流,忽略换行符 |
copy(InputStream input,OutputStream output) | 将输入流中的内容拷贝到输出流中,并可以指定字符编码 此方法有多个重载方法,满足不同的输入输出流 |
copyLarge(InputStream input,OutputStream output) | 将输入流中的内容拷贝到输出流中,适合大于2G内容的拷贝 |
LineIterator lineIterator(InputStream input,Charset charset) | 读取流,返回迭代器 |
read(InputStream input,byte[] buffer) | 从一个流中读取内容 |
readFully(InputStream input,byte[] buffer) | 将输入流中的所有内容读入到字节数组中 |
List<String> readLines(InputStream input,Charset charset) | 字符串读写 |
String resourceToString(String name,Charset charset) | |
URL resourceToURL(String name) | |
long skip(InputStream input,long toSkip) | 跳过指定长度的流 |
skipFully(InputStream input,long toSkip) | 类似skip,只是如果忽略的长度大于现有的长度,会抛出异常 |
toBufferedInputStream(InputStream input) | 获取一个缓冲输入流,默认缓冲大小 1KB |
toBufferedReader(Reader reader) | 获取一个字符缓冲流 |
toByteArray(InputStream inputStream) | 将输入流转换成字符数组 |
toInputStream(CharSequence input,Charset charset) | 通过文本获取输入流 , 可以指定编码格式 |
toString(InputStream input,Charset charset) | 将输入流转换成字符串 |
write(byte[] data,OutputStream output) | 把数据写入到输出流中 |
@Test
public void testIOUtils() throws IOException, URISyntaxException {
String fileDir = "/Users/dllwh/Downloads/test";
String file1 = fileDir + File.separator + "aa.txt";
String file2 = fileDir + File.separator + "bb.txt";
String charsetName = "UTF-8";
String urlStr = "http://www.baidu.com";
FileInputStream fileInputStream1 = new FileInputStream(file1);
FileInputStream fileInputStream2 = new FileInputStream(file2);
FileOutputStream outputStream = new FileOutputStream(file1);
FileReader fileReader1 = new FileReader(file1);
FileReader fileReader2 = new FileReader(file1);
FileWriter fileWriter = new FileWriter(file1);
/**
* 1、静态变量
*/
//
System.out.println("1.1 获取文件路径分隔符字符: " + IOUtils.DIR_SEPARATOR);
System.out.println("1.2 获取Unix系统文件路径分隔符字符: " + IOUtils.DIR_SEPARATOR_UNIX);
System.out.println("1.3 获取windows系统文件路径分隔符: " + IOUtils.DIR_SEPARATOR_WINDOWS);
System.out.println("1.4 获取行分隔符: " + IOUtils.LINE_SEPARATOR);
System.out.println("1.5 获取Unix系统行分隔符: " + IOUtils.LINE_SEPARATOR_UNIX);
System.out.println("1.6 获取windows系统行分隔符: " + IOUtils.LINE_SEPARATOR_WINDOWS);
System.out.println("===================================================================");
/**
* 2、静态方法
*/
//2.1获取输入流
System.out.println("2.1 根据InputStream获取BufferedInputStream: " + IOUtils.buffer(fileInputStream1));
System.out.println("2.2 根据outputStream获取BufferedOutputStream: " + IOUtils.buffer(outputStream));
System.out.println("2.3 根据reader获取BufferedReader: " + IOUtils.buffer(fileReader1));
System.out.println("2.4 从InputStream输入流中获取行数据: ");
List<String> lineContent = IOUtils.readLines(fileInputStream1, "UTF-8");
lineContent.forEach(s -> System.out.println(s));
System.out.println("2.5 从Reader输入流中获取行数据: ");
IOUtils.readLines(fileReader1).forEach(s -> System.out.println(s));
byte[] data = IOUtils.toByteArray(fileInputStream1);
System.out.println("2.6 从inputStream获取文件字节数组: " + data);
System.out.println("2.7 从reader获取文件字节数组,并指定编码: " + IOUtils.toByteArray(fileReader1, charsetName));
System.out.println("2.8 从url资源中获取文件字节数组: " + IOUtils.toByteArray(new URI(urlStr)));
char[] charData = IOUtils.toCharArray(fileInputStream1, "UTF-8");
System.out.println("2.9 从InputStream输入流获取字符数据: " + charData);
System.out.println("2.10 从reader输入流中获取字符数组: " + IOUtils.toCharArray(fileReader1));
System.out.println("2.11 从InputStream输入流中获取字符串数据: " + IOUtils.toString(fileInputStream1, charsetName));
System.out.println("2.12 从reader输入流中获取字符串数据: " + IOUtils.toString(fileReader1));
System.out.println("2.13 从url中获取字符串数据: " + IOUtils.toString(new URI(urlStr), charsetName));
System.out.println("===================================================================");
/**
* 3、写数据
*/
System.out.println("3.1 将字节数组数据通过Writer写到文件,并指明编码");
IOUtils.write(data, fileWriter, charsetName);
System.out.println("3.2 将字节数组数据通过outputStream写到文件");
IOUtils.write(charData, outputStream, charsetName);
System.out.println("3.3 将字符数组数据通过writer写到文件");
IOUtils.write(charData, fileWriter);
System.out.println("3.4 将字符串数据通过OutpurStream输出流,写到文件");
IOUtils.write("流光逝,步蹒跚,碎银几两汉子难。", outputStream, charsetName);
System.out.println("3.5 将字符串数据通过Writer输出流写到文件");
IOUtils.write("也曾心怀青云志,回首只盼老少安。", fileWriter);
System.out.println("3.6 将集合数据通关outputStream输出流写到文件");
IOUtils.writeLines(lineContent, "UTF-8", outputStream, charsetName);
System.out.println("3.7 将集合数据通过writer输出流写到文件");
IOUtils.writeLines(lineContent, "UTF-8", fileWriter);
System.out.println("===================================================================");
/**
* 4、获取文件输入迭代器
*/
System.out.println("4.1 从inputStream输入流中获取行迭代器");
LineIterator lineIterator = IOUtils.lineIterator(fileInputStream1, charsetName);
System.out.println("4.2 从Reader输入流中获取行迭代器");
LineIterator lineIterator1 = IOUtils.lineIterator(fileReader1);
System.out.println("===================================================================");
/**
* 5、复制文件
*/
System.out.println("5.1 复制文件输入流到输出流: "+IOUtils.copy(fileInputStream1, outputStream));
System.out.println("5.2 复制文件输入流到输出流,并设置缓冲大小: "+IOUtils.copy(fileInputStream1, outputStream, 1024));
System.out.println("5.3 复制InputStream文件到输出流Writer,并设置输出流编码:");
IOUtils.copy(fileInputStream1, fileWriter, charsetName);
System.out.println("5.4 复制reader文件到writer");
IOUtils.copy(fileReader1, fileWriter);
System.out.println("5.5 从inputStream复制大文件到outputStream,文件大小超过2g:");
IOUtils.copy(fileInputStream1, outputStream);
System.out.println("5.6 从reader复制大文件到writer,文件大小超过2g:");
IOUtils.copy(fileReader1, fileWriter);
System.out.println("===================================================================");
/**
* 6、IO流比较
*/
System.out.println("6.1 比较两个InputStream是否相等: "+IOUtils.contentEquals(fileInputStream1, fileInputStream2));
System.out.println("6.2 判断两个reader是否相等: "+IOUtils.contentEquals(fileReader1, fileReader2));
}
2.1.2 FilenameUtils
FilenameUtils 包含一些工具类,它们基于文件名工作而不是File对象。它以类似的方式在不同的操作系统上运行,解决了从基于Windows的开发环境转移到基于Unix的生产环境时的问题。
方法 | 说明 |
---|---|
String concat(String basePath,String fileName) | 合并目录和文件名为文件全路径 |
directoryContains(String directory,String child) | 判断目录下是否包含指定文件或目录 |
equals(String fileName1,String fileName2) | 判断文件路径是否相同 |
String getBaseName(String fileName) | 获取去除目录和后缀后的文件名 |
String getExtension(String fileName) | 获取文件的后缀 |
String getFullPath(String fileName) | 获取文件的目录 |
String getName(String fileName) | 获取文件名,包括后缀 |
String getPath(String fileName) | 去除盘符后的路径 |
String getPrefix(String fileName) | 获取前缀,即所谓的盘符 |
indexOfExtension(String fileName) | 获取最后一个.的位置 |
indexOfLastSeparator(String fileName) | 获取最后一个/的位置 |
isExtension(String fileName,String… extension) | 判断文件扩展名是否包含在指定集合中 |
String normalize(String fileName,boolean separator) | 获取当前系统格式化路径 |
String removeExtension(String fileName) | 移除文件的扩展名 |
String separatorsToSystem(String path) | 转换分隔符为当前系统分隔符 |
String separatorsToUnix(String path) | 转换分隔符为linux系统分隔符 |
String separatorsToWindows(String path) | 转换分隔符为windows系统分隔符 |
wildcardMatch(String fileName,String matcher) | 判断文件扩展名是否和指定规则匹配 |
@Test
public void testFilenameUtil() {
String fileDir = "/Users/dllwh/Downloads";
String file1 = fileDir + File.separator + "07e92f6d1ec2b1aaa0fcabe135413a20.jpg";
String file2 = fileDir + File.separator + "1bf898a2a6986716634299d0f16eda99.jpg";
String file3 = fileDir + File.separator + "8ee0d1306cfd7fa00340199ff859b03d.jpg";
System.out.println("1.判断父目录是否包含子元素(文件或目录): " + FilenameUtils.directoryContains(fileDir, file2));
System.out.println("2.判断两个文件名是否相等: " + FilenameUtils.equals(fileDir, file1));
System.out.println("3.两个文件名标准化后判断是否相等: " + FilenameUtils.equalsNormalized(fileDir, file1));
System.out.println("4.获取文件基本名: " + FilenameUtils.getBaseName(file3));
System.out.println("5.获取文件扩展名: " + FilenameUtils.getExtension(file3));
System.out.println("6.获取文件完整路径,不含文件名: " + FilenameUtils.getFullPath(file3));
System.out.println("7.获取文件不含结尾分隔符的完整路径,不含文件名: " + FilenameUtils.getFullPathNoEndSeparator(file3));
System.out.println("8.获取单独的文件名和后缀: " + FilenameUtils.getName(file3));
System.out.println("9.获取不含前缀的完整文件路径,不含文件名: " + FilenameUtils.getPath(file3));
System.out.println("10.获取不含前缀和结尾分隔符的完整文件路径,不含文件名: " + FilenameUtils.getPathNoEndSeparator(file3));
System.out.println("11.获取文件路径前缀: " + FilenameUtils.getPrefix(file3));
System.out.println("12.获取文件路径前缀长度: " + FilenameUtils.getPrefixLength(file3));
System.out.println("13.获取文件扩展索引: " + FilenameUtils.indexOfExtension(file3));
System.out.println("14.获取文件最后一个分隔符索引: " + FilenameUtils.indexOfLastSeparator(file3));
List<String> suffixList = new ArrayList<String>();
suffixList.add("png");
suffixList.add("txt");
suffixList.add("xlsx");
System.out.println("15.判断文件扩展名是否符合给定的: " + FilenameUtils.isExtension(file3, suffixList));
System.out.println("16.判断文件扩展名是否符合指定的: " + FilenameUtils.isExtension(file3, "jpg"));
System.out.println("17.标准化文件路径: " + FilenameUtils.normalize(file3));
System.out.println("18.标准化文件路径,不含最后的结尾分隔符: " + FilenameUtils.normalizeNoEndSeparator(file3));
System.out.println("19.获取不含后缀的文件路径和文件名: " + FilenameUtils.removeExtension(file3));
System.out.println("20.转换文件分隔符为系统分隔符: " + FilenameUtils.separatorsToSystem(file3));
System.out.println("21.转换文件分隔符为Unix系统分隔符: " + FilenameUtils.separatorsToUnix(file3));
System.out.println("22.转换文件分割符为windows系统分隔符: " + FilenameUtils.separatorsToWindows(file3));
System.out.println("23.判断文件名是否符合指定的规则: " + FilenameUtils.wildcardMatch(file3, "*.jpg"));
}
2.1.3 FileUtils
包含了文件操作的相关方法,如移动、打开、检查存在、读取文件等。
方法 | 说明 |
---|---|
String byteCountToDisplaySize(BigInteger size) | |
void cleanDirectory(File directory) | 清空文件夹里面的所有内容(包括子文件夹、子文件) |
boolean contentEquals(File file1,File file2) | 比较两个文件内容是否相同 |
copyDirectory(File srcDir,File destDir) | 将一个目录内容复制到另一个目录 |
copyDirectoryToDirectory(File sourceDir,File destDir) | 以子目录的形式将文件夹复制到到另一个文件夹下 |
copyFile(File srcFile,File destFile) | 复制文件 |
copyFileToDirectory(File srcFile,File destDir) | 将文件复制到某个目录下 |
copyInputStreamToFile(InputStream source,File dest) | 将输入流中的内容复制到某个文件 |
copyToDirectory(File sourceFile,File destDir) | |
copyToFile(InputStream inputStream,File file) | |
copyURLToFile(URL source,File destination) | 把URL 里面内容复制到文件(可以下载文件) |
File delete(File file) | 删除 |
void deleteDirectory(File directory) | 删除文件夹,包括文件夹和文件夹里面所有的文件 |
boolean deleteQuietly(File file) | 删除文件 |
directoryContains(File directory,File child) | 判断文件夹内是否包含某个文件或者文件夹 |
void forceDelete(File file) | 强制删除文件,若文件不存在则会抛出异常 |
void forceDeleteOnExit(File file) | |
void forceMkdir(File directory) | 创建文件夹(可创建多级) |
void forceMkdirParent(File file) | 创建文件的父级目录 |
File getFile(File directory,String… names) | 从指定的文件夹中获取文件 |
File getFile(String… names) | |
File getTempDirectory() | 获取临时目录文件 |
String getTempDirectoryPath() | 获取临时目录路径 |
File getUserDirectory() | 获取用户目录文件 |
String getUserDirectoryPath() | 获取用户目录路径 |
boolean isFileNewer(File file,File reference) | 判断file 跟 reference比是否是新文件 |
boolean isFileNewer(File file,Date date) | 在指定的日期判断文件是否是新文件 |
boolean isFileOlder(File file,File reference) | |
boolean isRegularFile(File file,LinkOption… options) | |
boolean isSymlink(File file) | 判断是否是符号链接 |
LineIterator lineIterator(final File file) | |
listFiles(File directory,IOFileFilter fileFilter,IOFileFilter dirFilter) | 列出指定目录下的文件 |
listFiles(File directory,String[] extensions,boolean recursive) | 是否递归查找指定扩展名的文件 |
listFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) | 查询目录下的所有文件,并可用filter进行过滤 |
moveDirectory(File srcDir,File destDir) | 文件夹在内的所有文件都将移动 |
moveDirectoryToDirectory(File src,File destDir,boolean createDestDir) | 以子文件夹的形式移动到另外一个文件下 |
moveFile(File srcFile,File destFile) | 移动文件 |
moveFileToDirectory(File srcFile,File destDir,boolean createDestDir) | 以子文件的形式移动到另外一个文件夹下 |
moveToDirectory(File src,File destDir,boolean createDestDir) | 移动文件或者目录到指定的文件夹内 |
FileInputStream openInputStream(File file) | 获取文件读取流,默认直接覆盖文件内容 |
FileOutputStream openOutputStream(File file,boolean append) | 获取文件输出流并指定是否追加到文件中 |
byte[] readFileToByteArray(File file) | 把文件读取到字节数组 |
String readFileToString(File file,String charsetName) | 把文件读取成字符串 |
List<String> readLines(File file,String charsetName) | 把文件读取成字符串集合 |
long sizeOf(File file) | 获取文件或者文件夹的大小 |
File toFile(URL url) | |
File[] toFiles(URL… urls) | |
touch(final File file) | 创建空文件 |
write(File file,CharSequence data,String charsetName) | 往文件里面写内容 |
writeByteArrayToFile(File file,byte[] data,int off,int len,boolean append) | 写入文件,文件不存在则自动创建,并指定是否追加 |
writeLines(File file,Collection<?> lines,String lineEnding,boolean append) | 按行写入文件,文件不存在自动则创建,并指定是否追加 |
writeStringToFile(File file,String data,String charsetName,boolean append) | 指定编码、是否以追加的方式写入文件 |
@Test
public void testFileUtil() throws IOException {
String fileDirPath = "/Users/dllwh/Downloads/test";
String destDirPath = "/Users/dllwh/Downloads/test1";
String file1Name = "aa.txt";
String file2Nme = "bb.txt";
/**
* 1、创建文件\文件夹
*/
File file = FileUtils.getFile(new File(fileDirPath), file1Name);
System.out.println("1.1 从文件夹中获取指定文件: " + file);
System.out.println("1.2 获取获取临时文件: " + FileUtils.getTempDirectory());
System.out.println("1.3 获取临时文件路径: " + FileUtils.getTempDirectoryPath());
System.out.println("1.4 获取用户文件: " + FileUtils.getUserDirectory());
System.out.println("1.5 获取用户文件路径: " + FileUtils.getUserDirectoryPath());
System.out.println("1.6 强制创建文件夹");
FileUtils.forceMkdir(new File(fileDirPath));
System.out.println("1.7 强制创建父文件夹");
FileUtils.forceMkdirParent(new File(fileDirPath, file1Name));
System.out.println("===================================================================");
/**
* 2、删除文件
*/
System.out.println("2.1 删除文件夹中的内容(包括子文件夹和子文件)");
FileUtils.cleanDirectory(new File(fileDirPath));
System.out.println("2.2 温和的删除文件,不抛出异常");
FileUtils.deleteQuietly(new File(fileDirPath, file1Name));
System.out.println("2.3 强制删除文件,文件需要存在,否则会抛出异常");
FileUtils.touch(new File(fileDirPath,file1Name));
FileUtils.forceDelete(new File(fileDirPath, file1Name));
System.out.println("2.4 JVM退出时强制删除文件");
FileUtils.forceDeleteOnExit(new File(fileDirPath, file1Name));
System.out.println("===================================================================");
/**
* 3、修改文件
*/
System.out.println("3.1 移动文件夹");
if (new File(destDirPath).exists()) {
FileUtils.forceDelete(new File(destDirPath));
}
FileUtils.moveDirectory(new File(fileDirPath), new File(destDirPath));
System.out.println("3.2 将文件移到指定的文件夹");
FileUtils.touch(new File(fileDirPath, file1Name));
FileUtils.moveFileToDirectory(new File(fileDirPath, file1Name), new File(destDirPath), true);
System.out.println("3.3 移动文件或文件夹到指定的文件夹");
FileUtils.moveToDirectory(new File(destDirPath, file1Name), new File(fileDirPath), true);
System.out.println("===================================================================");
/**
* 4、文件查找
*/
System.out.println("4.1 是否递归查找指定扩展名的文件");
String[] extensions = new String[]{"txt", "jpg", "png"};
Collection<File> fileList = FileUtils.listFiles(new File(fileDirPath), extensions, true);
fileList.forEach(f -> System.out.println(f.getAbsolutePath()));
System.out.println("===================================================================");
/**
* 5、读取文件
*/
System.out.println("5.1 根据文件获取文件输入流: " + FileUtils.openInputStream(new File(fileDirPath,file1Name)));
byte[] bytes = FileUtils.readFileToByteArray(new File(fileDirPath,file1Name));
System.out.println("5.2 读取文件到字节数组: " + Arrays.toString(bytes));
String fileContent = FileUtils.readFileToString(new File(fileDirPath,file1Name), "UTF-8");
System.out.println("5.3 读取文件到字符串: " + fileContent);
System.out.println("5.4 读取文件到集合中: ");
List<String> fileContentList = FileUtils.readLines(new File(fileDirPath,file1Name), "UTF-8");
fileContentList.forEach(System.out::println);
System.out.println("5.5 获取文件大小: " + FileUtils.sizeOf(new File(fileDirPath,file1Name)));
System.out.println("===================================================================");
/**
* 6、写文件
*/
System.out.println("6.1 根据文件获取输出流: " + FileUtils.openOutputStream(new File(fileDirPath,file1Name)));
System.out.println("6.2 获取文件输出流并指定是否追加到文件中: " + FileUtils.openOutputStream(new File(fileDirPath,file1Name), true));
System.out.println("6.3 将字节数组内容写到文件中,文件不存在时创建: ");
FileUtils.writeByteArrayToFile(new File(fileDirPath,file1Name), bytes);
System.out.println("6.4 将字节数组内容写到文件中,文件不存在时创建,并指定是否追加: ");
FileUtils.writeByteArrayToFile(new File(fileDirPath,file1Name), bytes, true);
System.out.println("6.5 将集合数据按行写到文件中: ");
FileUtils.writeLines(new File(fileDirPath,file1Name), fileContentList);
System.out.println("6.6 将集合数据按行写到文件中,并指定是否追加: ");
FileUtils.writeLines(new File(fileDirPath,file1Name), fileContentList, true);
System.out.println("6.7 将字符串写到文件中,并指定编码: ");
FileUtils.writeStringToFile(file, fileContent, "UTF-8");
System.out.println("6.8 将字符串数据写到文件中,并指定编码和是否追加的方式: ");
FileUtils.writeStringToFile(file, fileContent, "UTF-8", true);
System.out.println("===================================================================");
/**
* 7、复制文件
*/
System.out.println("7.1 复制文件目录中的内容到另一个目录");
File fileDir = new File(fileDirPath);
File destDir = new File(destDirPath);
FileUtils.copyDirectory(fileDir, destDir);
System.out.println("7.2 复制文件目录,并指定是否保存文件日期");
FileUtils.copyDirectory(fileDir, destDir, true);
System.out.println("7.3 使用文件过滤器过滤文件");
FileUtils.copyDirectory(fileDir, destDir, new NameFileFilter("aa"));
System.out.println("7.4 复制文件");
FileUtils.copyFile(new File(fileDirPath,file1Name), new File(destDirPath,file2Nme));
System.out.println("7.5 复制文件并指定是否保留文件日期");
FileUtils.copyDirectory(new File(fileDirPath), new File(destDirPath), true);
System.out.println("7.6 复制文件夹到目录");
FileUtils.copyFileToDirectory(new File(fileDirPath,file1Name), destDir);
System.out.println("7.7 将url资源复制到指定文件");
FileUtils.copyURLToFile(new URL("http://www.baidu.com"), file);
System.out.println("===================================================================");
/**
* 8、文件过滤
*/
System.out.println("8.1 列出子孙级目录或文件,带有过滤功能");
for (File f : FileUtils.listFiles(new File(fileDirPath), EmptyFileFilter.NOT_EMPTY, null)) {
System.out.println(f.getAbsolutePath());
}
System.out.println("===================================================================");
/**
* 9.文件比较与判断
*/
System.out.println("9.1 比较文件内容是否相同: " + FileUtils.contentEquals(new File(fileDirPath,file1Name), new File(destDirPath,file2Nme)));
System.out.println("9.2 判断一个文件夹是否包含另外一个文件夹: " + FileUtils.directoryContains(new File(fileDirPath), new File(destDirPath)));
System.out.println("9.3 判断文件是否新文件(isFileNewer): " + FileUtils.isFileNewer(new File(fileDirPath,file1Name), new Date()));
System.out.println("9.3 判断文件是否新文件(isFileOlder): " + FileUtils.isFileOlder(new File(fileDirPath,file1Name), new Date()));
System.out.println("9.3 判断文件和另外一个文件比是否是新的(isFileNewer): " + FileUtils.isFileNewer(new File(fileDirPath,file1Name), new File(destDirPath,file2Nme)));
System.out.println("9.3 判断文件和另外一个文件比是否是新的(isFileOlder): " + FileUtils.isFileOlder(new File(fileDirPath,file1Name), new File(destDirPath,file2Nme)));
System.out.println("===================================================================");
/**
* 10、涉及文件操作的数据转换
*/
System.out.println("10.1 将文件集合转换为文件数组");
for (File f : FileUtils.convertFileCollectionToFileArray(fileList)) {
System.out.println(f.getAbsolutePath());
}
System.out.println("10.2 将url资源转换为文件对象" + FileUtils.toFile(new URL("http://www.baidu.com")));
System.out.println("10.3 将多个url资源转换为文件数组");
File[] newUrlFiles1 = FileUtils.toFiles(new URL[]{});
for (File f : FileUtils.convertFileCollectionToFileArray(fileList)) {
System.out.println(f.getAbsolutePath());
}
System.out.println("10.4 将文件数组转化为url资源");
for (URL url : FileUtils.toURLs(newUrlFiles1)) {
System.out.println(url.getPath());
}
System.out.println("===================================================================");
/**
* 11、文件迭代
*/
System.out.println("11.1 文件迭代");
LineIterator iterator = FileUtils.lineIterator(new File(fileDirPath,file1Name), "UTF-8");
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
2.2 文件过滤器
org.apache.commons.io.filefilter 包定义了一个接口 (IOFileFilter),同时继承了 java.io.FileFilter 和 java.io.FilenameFilter接口。除此之外还提供了一系列可以使用的IOFileFilter接口实现,包括允许你组合其他过滤器。比如,这些过滤器可以用来遍历文件或在FileDialog中使用。
类别 | 过滤器名称 | 说明 |
---|---|---|
类型 | FileFileFilter | 仅接受文件 |
DirectoryFilter | 仅接受目录 | |
名称 | PrefixFileFilter | 基于前缀过滤文件 |
SuffixFileFilter | 根据后缀过滤文件,这用于检索特定类型的所有文件 | |
NameFileFilter | 基于文件名称过滤文件 | |
WildcardFileFilter | 基于通配符过滤文件 | |
RegexFileFilter | 基于正则表达式 | |
时间 | AgeFileFilter | 基于最后修改时间 |
大小 | EmptyFileFilter | 基于文件或目录是否为空 |
SizeFileFilter | 基于文件尺寸 | |
隐藏属性 | HiddenFileFilter | 基于文件或目录是否隐藏 |
读写属性 | CanReadFileFilter | 基于是否可读 |
CanWriteFileFilter | 基于是否可写入 | |
逻辑关系过滤器 | AndFileFilter | 基于AND逻辑运算 |
OrFileFilter | 基于OR逻辑运算 | |
NotFileFilter | 基于NOT逻辑运算 | |
工具类 | FileFilterUtils | 提供一些工厂方法用于生成各类文件过滤器 提供一些静态方法用于对指定的File集合进行过滤 |
@Test
public void testFileFilter() {
// 获取当前目录
File fileDir = new File(".");
/**
* 匹配文件名
*/
String[] acceptedNames = {"input", "input.txt"};
for (String file : fileDir.list(new NameFileFilter(acceptedNames, IOCase.INSENSITIVE))) {
System.out.println("File found, named: " + file);
}
System.out.println("=========================================");
/**
* 根据通配符匹配(过滤名称以t结尾的文件)
*/
for (String file : fileDir.list(new WildcardFileFilter("*t"))) {
System.out.println("Wildcard file found, named: " + file);
}
System.out.println("=========================================");
/**
* 匹配后缀(过滤扩展名为java的文件)
*/
for (String file : fileDir.list(new SuffixFileFilter("java"))) {
System.out.println("Suffix file found, named: " + file);
}
System.out.println("=========================================");
/**
* 匹配前缀
*/
for (String file : fileDir.list(new PrefixFileFilter("input"))) {
System.out.println("Prefix file found, named: " + file);
}
System.out.println("=========================================");
/**
* 逻辑或(过滤名称以 . 开头或以 t 结尾的文件)
*/
for (String file : fileDir.list(
new OrFileFilter(new PrefixFileFilter("."), new WildcardFileFilter("*t")))) {
System.out.println("Or file found, named: " + file);
}
System.out.println("=========================================");
/**
* 逻辑与(过滤名称以 . 开头并以 t 结尾的文件)
*/
for (String file : fileDir.list(
new AndFileFilter(new PrefixFileFilter("."), new WildcardFileFilter("*t")))) {
System.out.println("And/Not file found, named: " + file);
}
}
2.3 文件监控
由文件监控类中 FileAlterationMonitor
的线程按指定的间隔(默认为1000毫秒)不停的扫描文件观察器 FileAlterationObserver
,如果有文件的变化,则根据相关的文件比较器,判断文件时新增,还是删除,还是更改。在开始说明之前,先让我们来熟悉下跟文件监控相关的几个类。
监控类 | 说明 |
---|---|
FileEntry | 提供文件或目录的状态以及某个时间点的文件属性 |
FileAlterationObserver | 根目录下的文件状态,检查文件系统并通知侦听器创建、更改或删除事件 |
FileAlterationMonitor | 生成监视线程的线程,并以指定的时间间隔触发任何已注册的FileAlterationObserver |
接下来,看看是如何实现文件的监控,具体实现逻辑见如下:
- 创建一个FileAlterationObserver对象,传入一个要监控的目录,这个对象可以监控文件夹、文件的创建、删除和修改。
- 通过调用 addListener()方法,为observer对象添加一个 FileAlterationListener对象。
- 你可以通过很多种方式来创建,继承适配器类或者实现接口或者使用匿名内部类,实现所需要的监控方法。
- FileAlterationListener 提供了检测文件夹和文件的变化回调函数的接口以及观察模式回调的接口
- 创建一个FileAlterationMonitor 对象,将已经创建好的observer对象添加其中并且传入时间间隔参数(单位是毫秒)。
- 继承了Runnable接口,它检测文件的过程是采用一个线程去不停的进行文件的检测
- 调用start()方法即可开启监视器,如果你想停止监视器,调用stop()方法即可。
@Test
public void testFileMonitor() {
File inputFile = FileUtils.getFile("input.txt");
File parentDirectory = FileUtils.getFile(FilenameUtils.getFullPath(inputFile.getAbsolutePath()));
// 监听目录下文件变化。可通过参数控制监听某些文件,默认监听目录所有文件
FileAlterationObserver observer = new FileAlterationObserver(parentDirectory);
// 设置文件变化监听器
observer.addListener(new FileAlterationListenerAdaptor() {
@Override
public void onDirectoryCreate(File directory) {
System.out.println("目录创建: " + directory.getName());
}
@Override
public void onDirectoryChange(File directory) {
System.out.println("目录修改: " + directory.getName());
}
@Override
public void onDirectoryDelete(File directory) {
System.out.println("目录删除: " + directory.getName());
}
@Override
public void onFileCreate(File file) {
System.out.println("文件创建: " + file.getName());
}
@Override
public void onFileChange(File file) {
System.out.println("文件修改: " + file.getName());
}
@Override
public void onFileDelete(File file) {
System.out.println("文件删除: " + file.getName());
}
});
// 创建一个监视器,每隔500毫秒检查一次更改
FileAlterationMonitor monitor = new FileAlterationMonitor(500, observer);
try {
// 开始监控
monitor.start();
//create a new directory
File newFolder = new File("test");
File newFile = new File("test1");
newFolder.mkdirs();
Thread.sleep(1000);
newFile.createNewFile();
Thread.sleep(1000);
FileDeleteStrategy.NORMAL.delete(newFolder);
Thread.sleep(1000);
FileDeleteStrategy.NORMAL.delete(newFile);
Thread.sleep(1000);
// 停止监控
monitor.stop(10000);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
2.4 比较器
org.apache.commons.io.comparator
包为java.io.File
提供一些java.util.Comparator
实现,这些比较器可以用来排序列表。在 org.apache.commons.io.comparator包下有很多现成的文件比较器,可以对文件排序的时候直接拿来用,如下:
类型 | 说明 |
---|---|
CompositeFileComparator | 组合排序,将以下排序规则组合在一起 |
DefaultFileComparator | 默认文件比较器,直接使用File的compare方法 |
DirectoryFileComparator | 目录排在文件之前 |
ExtensionFileComparator | 扩展名比较器,按照文件的扩展名的ascii顺序排序,无扩展名的始终排在前面 |
LastModifiedFileComparator | 按照文件的最后修改时间排序 |
NameFileComparator | 按照文件名称排序 |
PathFileComparator | 按照路径排序,父目录优先排在前面 |
SizeFileComparator | 按照文件大小排序,小文件排在前面(目录会计算其总大小) |
通过查看源码,上面几个类都有着compare、sort、toString()等方法。
@Test
public void testFileComparator() {
// 获取当前目录
File dirFile = new File(".");
NameFileComparator comparator = new NameFileComparator(IOCase.SENSITIVE);
for (File file : comparator.sort(dirFile.listFiles())) {
System.out.println(file.getAbsolutePath());
}
System.out.println("=========================================");
SizeFileComparator sizeComparator = new SizeFileComparator(true);
for (File file : sizeComparator.sort(dirFile.listFiles())) {
System.out.println(file.getName() + " with size (kb): " + file.length());
}
System.out.println("=========================================");
LastModifiedFileComparator lastModified = new LastModifiedFileComparator();
for (File file : lastModified.sort(dirFile.listFiles())) {
Date modified = new Date(file.lastModified());
System.out.println(file.getName() + " last modified on: " + modified);
}
}
2.5 输入、输出
org.apache.commons.io.input
和 org.apache.commons.io.output
包中许多好用的过滤流,下面列举几个做下说明:
流 | 说明 |
---|---|
AutoCloseInputStream | 自动关闭的输入流 |
ReversedLinesFileReader | 倒序文件读取 |
CountingInputStream | 带计数功能的流 |
CountingOutputStream | 带计数功能的流 |
ObservableInputStream | 可观察的输入流(典型的观察者模式),可实现边读取边处理 |
BOMInputStream | 同时读取文本文件的bom头 |
BoundedInputStream | 有界的流,控制只允许读取前x个字节 |
CharSequenceInputStream | 支持StringBuilder、StringBuffer等读取 |
/**
* AutoCloseInputStream是一个过滤流,用来包装其他流,读取完后流会自动关掉
* 实现原理很简单,当读取完后将底层的流关闭,然后创建一个ClosedInputStream赋值给它包装的输入流。
* 注:如果输入流没有全部读取是不会关掉底层流的
*/
@Test
public void autoCloseDemo() throws Exception {
InputStream is = new FileInputStream("test.txt");
AutoCloseInputStream autoCloseInputStream = new AutoCloseInputStream(is);
// 将流全部读完
IOUtils.toByteArray(autoCloseInputStream);
// 可以省略关闭流的逻辑了
}
/**
* 大家都知道只给一个输入流咱们是没办法准确的知道它的大小的,虽说流提供了available()方法
* 但是这个方法只有在ByteArrayInputStream的情况下拿到的是准确的大小,其他如文件流网络流等都是不准确的
* (当然用野路子也可以实现,比如写入临时文件通过File.length()方法获取,然后在将文件转换为文件流)
* 下面这个流可以实现计数功能,当把文件读完大小也就计算出来了
*/
@Test
public void countingDemo() throws FileNotFoundException {
InputStream is = new FileInputStream("test.txt");
try (CountingInputStream cis = new CountingInputStream(is)) {
// 文件内容
String txt = IOUtils.toString(cis, "UTF-8");
// 读取的字节数
long size = cis.getByteCount();
} catch (IOException e) {
// 异常处理
}
}
private class MyObservableInputStream extends ObservableInputStream {
class MyObserver extends Observer {
@Override
public void data(final int input) throws IOException {
// 做自定义处理
}
@Override
public void data(final byte[] input, final int offset, final int length) throws IOException {
// 做自定义处理
}
}
public MyObservableInputStream(InputStream inputStream) {
super(inputStream);
}
}