百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

程序员的福音 - Apache Commons IO

csdh11 2025-05-05 14:54 1 浏览

此文是系列文章第三篇,前几篇请点击链接查看

程序猿的福音 - Apache Commons简介

程序员的福音 - Apache Commons Lang


Apache Commons IO是对java.io的扩展,主要是对Java中的bio封装了一些好用的工具类,nio涉及的较少,关于bio和nio问题我们后续再聊。

Commons IO目前最新版本是2.10.0,最低要求Java8以上。


包结构如下:

org.apache.commons.io
org.apache.commons.io.comparator
org.apache.commons.io.file
org.apache.commons.io.filefilter
org.apache.commons.io.function
org.apache.commons.io.input
org.apache.commons.io.monitor
org.apache.commons.io.output
org.apache.commons.io.serialization

下面只列举其中常用的加以说明,其余感兴趣的可以自行翻阅源码研究。


01

IOUtils

IOUtils可以说是Commons IO中最常用的了,下面直接看例子。

1. 关闭流

InputStream inputStream = new FileInputStream("test.txt");
OutputStream outputStream = new FileOutputStream("test.txt");
// 原生写法
if (inputStream != null) {
    try {
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
if (outputStream != null) {
    try {
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// commons写法(可以传任意数量的流)
IOUtils.closeQuietly(inputStream, outputStream);


2. 读取流

// ==== 输入流转换为byte数组 ====
// 原生写法
InputStream is = new FileInputStream("foo.txt");
byte[] buf = new byte[1024];
int len;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((len = is.read(buf)) != -1) {
    out.write(buf, 0, len);
}
byte[] result = out.toByteArray();
// commons写法
byte[] result2 = IOUtils.toByteArray(is);


// ---------------------------------------


// ==== 输入流转换为字符串 ====
// 原生写法
InputStream is = new FileInputStream("foo.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
    sb.append(line);
}
String result = sb.toString();
// commons写法
String result2 = IOUtils.toString(is, "UTF-8");


// IOUtils.toString 还有很多重载方法,保证有你想要的
// 将reader转换为字符串
String toString(Reader reader, String charset) throws IOException;
// 将url转换为字符串,也就是可以直接将网络上的内容下载为字符串
String toString(URL url, String charset) throws IOException;


3. 其他

// 按照行读取结果
InputStream is = new FileInputStream("test.txt");
List<String> lines = IOUtils.readLines(is, "UTF-8");


// 将行集合写入输出流
OutputStream os = new FileOutputStream("newTest.txt");
IOUtils.writeLines(lines, System.lineSeparator(), os, "UTF-8");


// 拷贝输入流到输出流
InputStream inputStream = new FileInputStream("src.txt");
OutputStream outputStream = new FileOutputStream("dest.txt");
IOUtils.copy(inputStream, outputStream);



02

文件相关

文件相关主要有FileUtils:文件工具类,FilenameUtils:文件名工具类,PathUtils:路径工具类(主要是操作JDK7新增的java.nio.file.Path类)

1. 文件读写

File readFile = new File("test.txt");
// 读取文件
String str = FileUtils.readFileToString(readFile, "UTF-8");
// 读取文件为字节数组
byte[] bytes = FileUtils.readFileToByteArray(readFile);
// 按行读取文件
List<String> lines =  FileUtils.readLines(readFile, "UTF-8");


File writeFile = new File("out.txt");
// 将字符串写入文件
FileUtils.writeStringToFile(writeFile, "测试文本", "UTF-8");
// 将字节数组写入文件
FileUtils.writeByteArrayToFile(writeFile, bytes);
// 将字符串列表一行一行写入文件
FileUtils.writeLines(writeFile, lines, "UTF-8");


2. 移动和复制

File srcFile = new File("src.txt");
File destFile = new File("dest.txt");
File srcDir = new File("/srcDir");
File destDir = new File("/destDir");
// 移动/拷贝文件
FileUtils.moveFile(srcFile, destFile);
FileUtils.copyFile(srcFile, destFile);
// 移动/拷贝文件到目录
FileUtils.moveFileToDirectory(srcFile, destDir, true);
FileUtils.copyFileToDirectory(srcFile, destDir);
// 移动/拷贝目录
FileUtils.moveDirectory(srcDir, destDir);
FileUtils.copyDirectory(srcDir, destDir);
// 拷贝网络资源到文件
FileUtils.copyURLToFile(new URL("http://xx"), destFile);
// 拷贝流到文件
FileUtils.copyInputStreamToFile(new FileInputStream("test.txt"), destFile);
// ... ...


3. 其他文件操作

File file = new File("test.txt");
File dir = new File("/test");
// 删除文件
FileUtils.delete(file);
// 删除目录
FileUtils.deleteDirectory(dir);
// 文件大小,如果是目录则递归计算总大小
long s = FileUtils.sizeOf(file);
// 则递归计算目录总大小,参数不是目录会抛出异常
long sd = FileUtils.sizeOfDirectory(dir);
// 递归获取目录下的所有文件
Collection<File> files = FileUtils.listFiles(dir, null, true);
// 获取jvm中的io临时目录
FileUtils.getTempDirectory();
// ... ...


4. 文件名称相关

// 获取名称,后缀等
String name = "/home/xxx/test.txt";
FilenameUtils.getName(name); // "test.txt"
FilenameUtils.getBaseName(name); // "test"
FilenameUtils.getExtension(name); // "txt"
FilenameUtils.getPath(name); // "/home/xxx/"


// 将相对路径转换为绝对路径
FilenameUtils.normalize("/foo/bar/.."); // "/foo"


5. JDK7的Path操作

// path既可以表示目录也可以表示文件


// 获取当前路径
Path path = PathUtils.current();
// 删除path
PathUtils.delete(path);
// 路径或文件是否为空
PathUtils.isEmpty(path);
// 设置只读
PathUtils.setReadOnly(path, true);
// 复制
PathUtils.copyFileToDirectory(Paths.get("test.txt"), path);
PathUtils.copyDirectory(Paths.get("/srcPath"), Paths.get("/destPath"));
// 统计目录内文件数量
Counters.PathCounters counters = PathUtils.countDirectory(path);
counters.getByteCounter(); // 字节大小
counters.getDirectoryCounter(); // 目录个数
counters.getFileCounter(); // 文件个数
// ... ...


03

流相关

org.apache.commons.io.input和org.apache.commons.io.output包下有许多好用的过滤流,下面列举几个做下说明

1. 自动关闭的输入流 AutoCloseInputStream

/**
 * AutoCloseInputStream是一个过滤流,用来包装其他流,读取完后流会自动关掉
 * 实现原理很简单,当读取完后将底层的流关闭,然后创建一个ClosedInputStream赋值给它包装的输入流。
 * 注:如果输入流没有全部读取是不会关掉底层流的
 */
public void autoCloseDemo() throws Exception {
    InputStream is = new FileInputStream("test.txt");
    AutoCloseInputStream acis = new AutoCloseInputStream(is);
    IOUtils.toByteArray(acis); // 将流全部读完
    // 可以省略关闭流的逻辑了
}


2. 倒序文件读取 ReversedLinesFileReader

// 从后向前按行读取
try (ReversedLinesFileReader reader = new ReversedLinesFileReader(new File("test.txt"), Charset.forName("UTF-8"))) {
    String lastLine = reader.readLine(); // 读取最后一行
    List<String> line5 = reader.readLines(5); // 从后再读5行
}


3. 带计数功能的流 CountingInputStream,CountingOutputStream

/**
 * 大家都知道只给一个输入流咱们是没办法准确的知道它的大小的,虽说流提供了available()方法
 * 但是这个方法只有在ByteArrayInputStream的情况下拿到的是准确的大小,其他如文件流网络流等都是不准确的
 * (当然用野路子也可以实现,比如写入临时文件通过File.length()方法获取,然后在将文件转换为文件流)
 * 下面这个流可以实现计数功能,当把文件读完大小也就计算出来了
 */
public void countingDemo() {
    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) {
        // 异常处理
    }
}


4. 可观察的输入流 ObservableInputStream

可观察的输入流(典型的观察者模式),可实现边读取边处理

比如将某些字节替换为另一个字节,计算md5摘要等

当然你也可以完全写到文件后在做处理,这样相当于做了两次遍历,性能较差。

这是一个基类,使用时需要继承它来扩展自己的流,示例如下:

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


5. 其他

BOMInputStream: 同时读取文本文件的bom头

BoundedInputStream:有界的流,控制只允许读取前x个字节

BrokenInputStream: 一个错误流,永远抛出IOException

CharSequenceInputStream: 支持StringBuilder,StringBuffer等读取

LockableFileWriter: 带锁的Writer,同一个文件同时只允许一个流写入,多余的写入操作会跑出IOException

StringBuilderWriter: StringBuilder的Writer

... ...


04

文件比较器


org.apache.commons.io.compare包有很多现成的文件比较器,可以对文件排序的时候直接拿来用。

DefaultFileComparator:默认文件比较器,直接使用File的compare方法。(文件集合排序( Collections.sort() )时传此比较器和不传效果一样)

DirectoryFileComparator:目录排在文件之前

ExtensionFileComparator:扩展名比较器,按照文件的扩展名的ascii顺序排序,无扩展名的始终排在前面


LastModifiedFileComparator
:按照文件的最后修改时间排序

NameFileComparator:按照文件名称排序

PathFileComparator:按照路径排序,父目录优先排在前面

SizeFileComparator:按照文件大小排序,小文件排在前面(目录会计算其总大小)

CompositeFileComparator:组合排序,将以上排序规则组合在一起


使用示例如下:

List<File> files = Arrays.asList(new File[]{
        new File("/foo/def"),
        new File("/foo/test.txt"),
        new File("/foo/abc"),
        new File("/foo/hh.txt")});
// 排序目录在前
Collections.sort(files, DirectoryFileComparator.DIRECTORY_COMPARATOR); // ["/foo/def", "/foo/abc", "/foo/test.txt", "/foo/hh.txt"]
// 排序目录在后
Collections.sort(files, DirectoryFileComparator.DIRECTORY_REVERSE); // ["/foo/test.txt", "/foo/hh.txt", "/foo/def", "/foo/abc"]
// 组合排序,首先按目录在前排序,其次再按照名称排序
Comparator dirAndNameComp = new CompositeFileComparator(
            DirectoryFileComparator.DIRECTORY_COMPARATOR,
            NameFileComparator.NAME_COMPARATOR);
Collections.sort(files, dirAndNameComp); // ["/foo/abc", "/foo/def", "/foo/hh.txt", "/foo/test.txt"]



05

文件监视器

org.apache.commons.io.monitor包主要提供对文件的创建、修改、删除的监听操作,下面直接看简单示例。

public static void main(String[] args) throws Exception {
    // 监听目录下文件变化。可通过参数控制监听某些文件,默认监听目录所有文件
    FileAlterationObserver observer = new FileAlterationObserver("/foo");
    observer.addListener(new myListener());
    FileAlterationMonitor monitor = new FileAlterationMonitor();
    monitor.addObserver(observer);
    monitor.start(); // 启动监视器
    Thread.currentThread().join(); // 避免主线程退出造成监视器退出
}


private class myListener extends FileAlterationListenerAdaptor {
    @Override
    public void onFileCreate(File file) {
        System.out.println("fileCreated:" + file.getAbsolutePath());
    }
    @Override
    public void onFileChange(File file) {
        System.out.println("fileChanged:" + file.getAbsolutePath());
    }
    @Override
    public void onFileDelete(File file) {
        System.out.println("fileDeleted:" + file.getAbsolutePath());
    }
}


06

总结

除了以上介绍的工具类外,还有其他不是很常用的就不多做介绍了。感兴趣的可以自行翻阅源码研究。

后续章节我将继续给大家介绍commons中其他好用的工具类库,期待你的关注。

相关推荐

NUS邵林团队发布DexSinGrasp基于强化学习实现物体分离与抓取统一

本文的作者均来自新加坡国立大学LinSLab。本文的共同第一作者为新加坡国立大学实习生许立昕和博士生刘子轩,主要研究方向为机器人学习和灵巧操纵,其余作者分别为硕士生桂哲玮、实习生郭京翔、江泽宇以及...

「PLC进阶」如何通过编写SCL语言程序实现物料分拣?

01、前言SCL作为IEC61131-3编程语言的一种,由于其高级语言的特性,特别适合复杂运算、复杂数学函数应用的场合。本文以FactoryIO软件中的物料分拣案例作为硬件基础,介绍如何通过SCL来实...

zk源码—5.请求的处理过程一(http1.1请求方法)

大纲1.服务器的请求处理链...

自己动手从0开始实现一个分布式 RPC 框架

前言为什么要自己写一个RPC框架,我觉得从个人成长上说,如果一个程序员能清楚的了解RPC框架所具备的要素,掌握RPC框架中涉及的服务注册发现、负载均衡、序列化协议、RPC通信协议、Socket通信、异...

MLSys’25 | 极低内存消耗:用SGD的内存成本实现AdamW的优化性能

AIxiv专栏是机器之心发布学术、技术内容的栏目。过去数年,机器之心AIxiv专栏接收报道了2000多篇内容,覆盖全球各大高校与企业的顶级实验室,有效促进了学术交流与传播。如果您有优秀的工作想要分享,...

线程池误用导致系统假死(线程池会自动销毁吗)

背景介绍在项目中,为了提高系统性能使用了RxJava实现异步方案,其中异步线程池是自建的。但是当QPS稍微增大之后却发现系统假死、无响应和返回,调用方出现大量超时现象。但是通过监控发现,系统线程数正常...

大型乘用车工厂布局规划(六大乘用车基地)

乘用车工厂的布局规划直接影响生产效率、物流成本、安全性和未来扩展能力。合理的布局应确保生产流程顺畅、物流高效、资源优化,并符合现代化智能制造和绿色工厂的要求。以下是详细的工厂布局规划要点:1.工厂布...

西门子 S7-200 SMART PLC 连接Factory IO的方法

有很多同学不清楚如何西门子200smart如何连接FactoryIO,本教程为您提供了如何使用西门子S7-200SMARTPLC连接FactoryIO的说明。设置PC和PLC之间的...

西门子博图高级仿真软件的应用(西门子博途软件仿真)

1.博图高级仿真软件(S7-PLCSIMAdvancedV2.0)S7-PLCSIMAdvancedV2.0包含大量仿真功能,通过创建虚拟控制器对S7-1500和ET200SP控制器进行仿真...

PLC编程必踩的6大坑——请对号入座,评论区见

一、缺乏整体规划:面条式代码问题实例:某快递分拣线项目初期未做流程图设计,工程师直接开始编写传送带控制程序。后期增加质检模块时发现I/O地址冲突,电机启停逻辑与传感器信号出现3处死循环,导致项目延期2...

统信UOS无需开发者模式安装软件包
统信UOS无需开发者模式安装软件包

原文链接:统信UOS无需开发者模式安装软件包...

2025-05-05 14:55 csdh11

100个Java工具类之76:数据指纹DigestUtils

为了提高数据安全性,保证数据的完整性和真实性,DigestUtils应运而生。正确恰当地使用DigestUtils的加密算法,可以实现数据的脱敏,防止数据泄露或篡改。...

麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包

#秋日生活打卡季#原文链接:...

Java常用工具类技术文档(java中工具类的作用)

一、概述Java工具类(UtilityClasses)是封装了通用功能的静态方法集合,能够简化代码、提高开发效率。本文整理Java原生及常用第三方库(如ApacheCommons、GoogleG...

软路由的用法(自动追剧配置)(软路由教学)

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:值友98958248861环境和需求...