java-Apache Commons IO

简介: Google的guava对Java的IO操作进行了一定封装,但是它更偏向于集合、并发和缓存,在实际项目中,我非常喜欢guava,同时我也非常喜欢Apache的一个工具包org.apache.commons.io,这两个工具包提供非常强大的工具能力,能够简化代码逻辑,提高开发效率和质量,是每个Java程序员都应该掌握的工具包.Apache Commons IO是Apache基金会创建并维护的Java函数库。

Google的guava对Java的IO操作进行了一定封装,但是它更偏向于集合、并发和缓存,在实际项目中,我非常喜欢guava,同时我也非常喜欢Apache的一个工具包org.apache.commons.io,这两个工具包提供非常强大的工具能力,能够简化代码逻辑,提高开发效率和质量,是每个Java程序员都应该掌握的工具包.Apache Commons IO是Apache基金会创建并维护的Java函数库。它提供了许多类使得开发者的常见任务变得简单,同时减少重复(boiler-plate)代码,这些代码可能遍布于每个独立的项目中,你却不得不重复的编写。这些类由经验丰富的开发者维护,对各种问题的边界条件考虑周到,并持续修复相关bug。

  • 工具类
  • 输入
  • 输出
  • 过滤器
  • 比较器
  • 文件监控器

http://commons.apache.org/proper/commons-io/download_io.cgi

public class ApacheCommonsExampleMain {

    public static void main(String[] args) {
        UtilityExample.runExample();

        FileMonitorExample.runExample();

        FiltersExample.runExample();

        InputExample.runExample();

        OutputExample.runExample();

        ComparatorExample.runExample();
    }
}

Utility Classes

org.apache.commons.io包中有很多工具类,里面多数类都是完成文件操作以及字符串比较的功能,下面列举了一下常用的工具类: FilenameUtils: 这个工具类是用来处理文件名(译者注:包含文件路径)的,他可以轻松解决不同操作系统文件名称规范不同的问题(比如windows和Unix)(在Unix系统以及Linux系统中文件分隔符是“/”,不支持”\“,windows中支持”\“以及”/“)。 FileUtils:提供文件操作(移动文件,读取文件,检查文件是否存在等等)的方法。 IOCase:提供字符串操作以及比较的方法。
FileSystemUtils:提供查看指定目录剩余空间的方法。

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileSystemUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.io.IOCase;

public final class UtilityExample {

    // We are using the file exampleTxt.txt in the folder ExampleFolder,
    // and we need to provide the full path to the Utility classes.
    private static final String EXAMPLE_TXT_PATH =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolderexampleTxt.txt";

    private static final String PARENT_DIR =
            "C:UsersLilykosworkspaceApacheCommonsExample";

    public static void runExample() throws IOException {
        System.out.println("Utility Classes example...");

        // FilenameUtils

        System.out.println("Full path of exampleTxt: " +
                FilenameUtils.getFullPath(EXAMPLE_TXT_PATH));

        System.out.println("Full name of exampleTxt: " +
                FilenameUtils.getName(EXAMPLE_TXT_PATH));

        System.out.println("Extension of exampleTxt: " +
                FilenameUtils.getExtension(EXAMPLE_TXT_PATH));

        System.out.println("Base name of exampleTxt: " +
                FilenameUtils.getBaseName(EXAMPLE_TXT_PATH));

        // FileUtils

        // We can create a new File object using FileUtils.getFile(String)
        // and then use this object to get information from the file.
        File exampleFile = FileUtils.getFile(EXAMPLE_TXT_PATH);
        LineIterator iter = FileUtils.lineIterator(exampleFile);

        System.out.println("Contents of exampleTxt...");
        while (iter.hasNext()) {
            System.out.println("t" + iter.next());
        }
        iter.close();

        // We can check if a file exists somewhere inside a certain directory.
        File parent = FileUtils.getFile(PARENT_DIR);
        System.out.println("Parent directory contains exampleTxt file: " +
                FileUtils.directoryContains(parent, exampleFile));

        // IOCase

        String str1 = "This is a new String.";
        String str2 = "This is another new String, yes!";

        System.out.println("Ends with string (case sensitive): " +
                IOCase.SENSITIVE.checkEndsWith(str1, "string."));
        System.out.println("Ends with string (case insensitive): " +
                IOCase.INSENSITIVE.checkEndsWith(str1, "string."));

        System.out.println("String equality: " +
                IOCase.SENSITIVE.checkEquals(str1, str2));

        // FileSystemUtils
        System.out.println("Free disk space (in KB): " + FileSystemUtils.freeSpaceKb("C:"));
        System.out.println("Free disk space (in MB): " + FileSystemUtils.freeSpaceKb("C:") / 1024);
    }
}

文件监控器

org.apache.commons.io.monitor包下的类包含的方法可以获取文件的指定信息,不过更重要的是,它可以创建处理器(handler)来跟踪指定文件或目录的变化并且可以在文件或目录发生变化的时候进行一些操作.

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileDeleteStrategy;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.commons.io.monitor.FileEntry;

public final class FileMonitorExample {

    private static final String EXAMPLE_PATH =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolderexampleFileEntry.txt";

    private static final String PARENT_DIR =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolder";

    private static final String NEW_DIR =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFoldernewDir";

    private static final String NEW_FILE =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFoldernewFile.txt";

    public static void runExample() {
        System.out.println("File Monitor example...");

        // FileEntry

        // We can monitor changes and get information about files
        // using the methods of this class.
        FileEntry entry = new FileEntry(FileUtils.getFile(EXAMPLE_PATH));

        System.out.println("File monitored: " + entry.getFile());
        System.out.println("File name: " + entry.getName());
        System.out.println("Is the file a directory?: " + entry.isDirectory());

        // File Monitoring

        // Create a new observer for the folder and add a listener
        // that will handle the events in a specific directory and take action.
        File parentDir = FileUtils.getFile(PARENT_DIR);

        FileAlterationObserver observer = new FileAlterationObserver(parentDir);
        observer.addListener(new FileAlterationListenerAdaptor() {

                @Override
                public void onFileCreate(File file) {
                    System.out.println("File created: " + file.getName());
                }

                @Override
                public void onFileDelete(File file) {
                    System.out.println("File deleted: " + file.getName());
                }

                @Override
                public void onDirectoryCreate(File dir) {
                    System.out.println("Directory created: " + dir.getName());
                }

                @Override
                public void onDirectoryDelete(File dir) {
                    System.out.println("Directory deleted: " + dir.getName());
                }
        });

        // Add a monior that will check for events every x ms,
        // and attach all the different observers that we want.
        FileAlterationMonitor monitor = new FileAlterationMonitor(500, observer);
        try {
            monitor.start();

            // After we attached the monitor, we can create some files and directories
            // and see what happens!
            File newDir = new File(NEW_DIR);
            File newFile = new File(NEW_FILE);

            newDir.mkdirs();
            newFile.createNewFile();

            Thread.sleep(1000);

            FileDeleteStrategy.NORMAL.delete(newDir);
            FileDeleteStrategy.NORMAL.delete(newFile);

            Thread.sleep(1000);

            monitor.stop();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用org.apache.commons.io.monitor包下的类创建了一个处理器来监听一些特定的事件(在上面的例子中就是我们对文件或目录所做的所有操作事件),为了获得这些信息,我们需要做以下几步操作:
1、创建一个File对象,这个对象指向我们需要监听变化的目录。
2、创建一个FileAlterationObserver对象,这个对象会观察这些变化。
3、通过调用addListener()方法,为observer对象添加一个 FileAlterationListenerAdaptor对象。你可以通过很多种方式来创建一个适配器,在我们的例子中我们使用内部类的方式进行创建并且只实现其中的一部分方法(只需要实现我们例子中需要用的方法即可)。
4、创建一个FileAlterationMonitor 对象,将已经创建好的observer对象添加其中并且传入时间间隔参数(单位是毫秒)。
5、调用start()方法即可开启监视器,如果你想停止监视器,调用stop()方法即可。

过滤器

过滤器可以以组合的方式使用并且它的用途非常多样。它可以轻松的区分不同的文件并且找到满足我们条件的文件。我们可以组合不同的过滤器来执行文件的逻辑比较并且精确的获取我们所需要文件,而无需使用冗余的字符串比较来寻找我们的文件。

import java.io.File;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.OrFileFilter;
import org.apache.commons.io.filefilter.PrefixFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;

public final class FiltersExample {

    private static final String PARENT_DIR =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolder";

    public static void runExample() {
        System.out.println("File Filter example...");

        // NameFileFilter
        // Right now, in the parent directory we have 3 files:
        //      directory example
        //      file exampleEntry.txt
        //      file exampleTxt.txt

        // Get all the files in the specified directory
        // that are named "example".
        File dir = FileUtils.getFile(PARENT_DIR);
        String[] acceptedNames = {"example", "exampleTxt.txt"};
        for (String file: dir.list(new NameFileFilter(acceptedNames, IOCase.INSENSITIVE))) {
            System.out.println("File found, named: " + file);
        }

        //WildcardFileFilter
        // We can use wildcards in order to get less specific results
        //      ? used for 1 missing char
        //      * used for multiple missing chars
        for (String file: dir.list(new WildcardFileFilter("*ample*"))) {
            System.out.println("Wildcard file found, named: " + file);
        }

        // PrefixFileFilter 
        // We can also use the equivalent of startsWith
        // for filtering files.
        for (String file: dir.list(new PrefixFileFilter("example"))) {
            System.out.println("Prefix file found, named: " + file);
        }

        // SuffixFileFilter
        // We can also use the equivalent of endsWith
        // for filtering files.
        for (String file: dir.list(new SuffixFileFilter(".txt"))) {
            System.out.println("Suffix file found, named: " + file);
        }

        // OrFileFilter 
        // We can use some filters of filters.
        // in this case, we use a filter to apply a logical 
        // or between our filters.
        for (String file: dir.list(new OrFileFilter(
                new WildcardFileFilter("*ample*"), new SuffixFileFilter(".txt")))) {
            System.out.println("Or file found, named: " + file);
        }

        // And this can become very detailed.
        // Eg, get all the files that have "ample" in their name
        // but they are not text files (so they have no ".txt" extension.
        for (String file: dir.list(new AndFileFilter( // we will match 2 filters...
                new WildcardFileFilter("*ample*"), // ...the 1st is a wildcard...
                new NotFileFilter(new SuffixFileFilter(".txt"))))) { // ...and the 2nd is NOT .txt.
            System.out.println("And/Not file found, named: " + file);
        }
    }
}

比较器

使用org.apache.commons.io.comparator 包下的类可以让你轻松的对文件或目录进行比较或者排序。你只需提供一个文件列表,选择不同的类就可以实现不同方式的文件比较

import java.io.File;
import java.util.Date;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.comparator.LastModifiedFileComparator;
import org.apache.commons.io.comparator.NameFileComparator;
import org.apache.commons.io.comparator.SizeFileComparator;

public final class ComparatorExample {

    private static final String PARENT_DIR =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolder";

    private static final String FILE_1 =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolderexample";

    private static final String FILE_2 =
            "C:UsersLilykosworkspaceApacheCommonsExampleExampleFolderexampleTxt.txt";

    public static void runExample() {
        System.out.println("Comparator example...");

        //NameFileComparator

        // Let's get a directory as a File object
        // and sort all its files.
        File parentDir = FileUtils.getFile(PARENT_DIR);
        NameFileComparator comparator = new NameFileComparator(IOCase.SENSITIVE);
        File[] sortedFiles = comparator.sort(parentDir.listFiles());

        System.out.println("Sorted by name files in parent directory: ");
        for (File file: sortedFiles) {
            System.out.println("t"+ file.getAbsolutePath());
        }

        // SizeFileComparator

        // We can compare files based on their size.
        // The boolean in the constructor is about the directories.
        //      true: directory's contents count to the size.
        //      false: directory is considered zero size.
        SizeFileComparator sizeComparator = new SizeFileComparator(true);
        File[] sizeFiles = sizeComparator.sort(parentDir.listFiles());

        System.out.println("Sorted by size files in parent directory: ");
        for (File file: sizeFiles) {
            System.out.println("t"+ file.getName() + " with size (kb): " + file.length());
        }

        // LastModifiedFileComparator

        // We can use this class to find which file was more recently modified.
        LastModifiedFileComparator lastModified = new LastModifiedFileComparator();
        File[] lastModifiedFiles = lastModified.sort(parentDir.listFiles());

        System.out.println("Sorted by last modified files in parent directory: ");
        for (File file: lastModifiedFiles) {
            Date modified = new Date(file.lastModified());
            System.out.println("t"+ file.getName() + " last modified on: " + modified);
        }

        // Or, we can also compare 2 specific files and find which one was last modified.
        //      returns > 0 if the first file was last modified.
        //      returns  0)
            System.out.println("File " + file1.getName() + " was modified last because...");
        else
            System.out.println("File " + file2.getName() + "was modified last because...");

        System.out.println("t"+ file1.getName() + " last modified on: " +
                new Date(file1.lastModified()));
        System.out.println("t"+ file2.getName() + " last modified on: " +
                new Date(file2.lastModified()));
    }
}

NameFileComparator:通过文件名来比较文件。
SizeFileComparator:通过文件大小来比较文件。
LastModifiedFileComparator:通过文件的最新修改时间来比较文件。
在这里你需要注意,比较可以在定的文件夹中(文件夹下的文件已经被sort()方法排序过了),也可以在两个指定的文件之间(通过使用compare()方法)。

输入

org.apache.commons.io.input包下有许多InputStrem类的实现,我们来测试一个最实用的类,TeeInputStream,将InputStream以及OutputStream作为参数传入其中,自动实现将输入流的数据读取到输出流中。而且,通过传入第三个参数,一个boolean类型参数,可以在数据读取完毕之后自动关闭输入流和输出流。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.input.TeeInputStream;
import org.apache.commons.io.input.XmlStreamReader;

public final class InputExample {

    private static final String XML_PATH =
            "C:UsersLilykosworkspaceApacheCommonsExampleInputOutputExampleFolderweb.xml";

    private static final String INPUT = "This should go to the output.";

    public static void runExample() {
        System.out.println("Input example...");
        XmlStreamReader xmlReader = null;
        TeeInputStream tee = null;

        try {

            // XmlStreamReader

            // We can read an xml file and get its encoding.
            File xml = FileUtils.getFile(XML_PATH);

            xmlReader = new XmlStreamReader(xml);
            System.out.println("XML encoding: " + xmlReader.getEncoding());

            // TeeInputStream

            // This very useful class copies an input stream to an output stream
            // and closes both using only one close() method (by defining the 3rd
            // constructor parameter as true).
            ByteArrayInputStream in = new ByteArrayInputStream(INPUT.getBytes("US-ASCII"));
            ByteArrayOutputStream out = new ByteArrayOutputStream();

            tee = new TeeInputStream(in, out, true);
            tee.read(new byte[INPUT.length()]);

            System.out.println("Output stream: " + out.toString());         
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try { xmlReader.close(); }
            catch (IOException e) { e.printStackTrace(); }

            try { tee.close(); }
            catch (IOException e) { e.printStackTrace(); }
        }
    }
}

输出

org.apache.commons.io.input包中的类相似, org.apache.commons.io.output包中同样有OutputStream类的实现,他们可以在多种情况下使用,一个非常有意思的类就是 TeeOutputStream,它可以将输出流进行分流,换句话说我们可以用一个输入流将数据分别读入到两个不同的输出流

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.commons.io.input.TeeInputStream;
import org.apache.commons.io.output.TeeOutputStream;

public final class OutputExample {

    private static final String INPUT = "This should go to the output.";

    public static void runExample() {
        System.out.println("Output example...");
        TeeInputStream teeIn = null;
        TeeOutputStream teeOut = null;

        try {

            // TeeOutputStream

            ByteArrayInputStream in = new ByteArrayInputStream(INPUT.getBytes("US-ASCII"));
            ByteArrayOutputStream out1 = new ByteArrayOutputStream();
            ByteArrayOutputStream out2 = new ByteArrayOutputStream();

            teeOut = new TeeOutputStream(out1, out2);
            teeIn = new TeeInputStream(in, teeOut, true);
            teeIn.read(new byte[INPUT.length()]);

            System.out.println("Output stream 1: " + out1.toString());
            System.out.println("Output stream 2: " + out2.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // No need to close teeOut. When teeIn closes, it will also close its
            // Output stream (which is teeOut), which will in turn close the 2
            // branches (out1, out2).
            try { teeIn.close(); }
            catch (IOException e) { e.printStackTrace(); }
        }
    }
}

庞大的函数库里面还有包含很多其他的功能

目录
相关文章
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
15天前
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
38 9
|
5月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
2月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
86 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
Java 数据处理 开发者
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
39 1
|
2月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
95 1
|
2月前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
60 0
|
3月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
224 12
|
2月前
|
存储 Java 程序员
【Java】文件IO
【Java】文件IO
39 0

推荐镜像

更多