- 浏览: 2876850 次
- 性别:
- 来自: 武汉
文章分类
- 全部博客 (1173)
- 名言警句 (5)
- 心情随笔 (50)
- 数据库 (57)
- Java基础 (241)
- J2EE框架 (91)
- 数据结构 (12)
- 程序设计 (21)
- WEB技术 (128)
- 网络日志 (12)
- IT资讯 (247)
- linux (64)
- solaris (2)
- 其它 (143)
- WebService (4)
- 日语学习 (2)
- 机器人 (5)
- Android (5)
- cgywin (3)
- Game (1)
- DWR (1)
- spring (8)
- canvas (1)
- Guava (3)
- Modbus (5)
- 测试 (6)
- mongodb (9)
- Quartz (2)
- Cron (1)
- windows (2)
- 持续集成 (1)
- bootstrap (3)
- 结对编程 (1)
- nodejs (1)
- Netty (1)
- 安全 (3)
- webstorm (2)
- sparkline (1)
- Job (1)
- git (3)
- Maven (3)
- knockout (5)
- jquery (1)
- bower (1)
- docker (1)
- confluence (4)
- wiki (1)
- GoogleMap (1)
- jekyll (10)
- ruby (2)
- npm (3)
- browserify (1)
- gulp (3)
- openwrt (1)
- discuz (3)
- 输入法 (1)
- JPA (1)
- eclipse (2)
- IntelliJ (1)
- css (1)
- 虚拟机 (1)
- 操作系统 (1)
- azkaban (2)
- scrum (1)
最新评论
-
pangxiea_:
你好, 想请问一下 Linux下 这么使用rxtxcomm 在 ...
使用Java进行串口通信 -
abababudei:
请教一下,这个您是怎么解决的:/dev/ttyS2enteri ...
Java应用程序的MODBUS通讯 -
xuniverse:
hannibal005 写道楼主,我问下 request.se ...
用javascript与java进行RSA加密与解密 -
atxkm:
找了一下午,终于找到了
gulp 拷贝文件时如何移除文件目录结构 -
kalogen:
gtczr 写道非常感谢,经过我自己的修改,已经完美实现。发出 ...
用javascript与java进行RSA加密与解密
【一】Apache commons IO简介
首先贴一段Apache commons IO官网上的介绍,来对这个著名的开源包有一个基本的了解:
Commons IO is a library of utilities to assist with developing IO functionality. There are four main areas included:
●Utility classes - with static methods to perform common tasks
●Filters - various implementations of file filters
●Comparators - various implementations of java.util.Comparator for files
●Streams - useful stream, reader and writer implementations
Packages |
|
This package defines utility classes for working with streams, readers, writers and files. |
|
This package provides various Comparator implementations for Files. |
|
This package defines an interface (IOFileFilter) that combines both FileFilter and FilenameFilter. |
|
This package provides implementations of input classes, such as InputStream and Reader. |
|
This |
【二】org.apache.comons.io.input包介绍
这个包针对SUN JDK IO包进行了扩展,实现了一些功能简单的IO类,主要包括了对字节/字符输入流接口的实现
<!--[if !supportLineBreakNewLine]-->
这个包针对java.io.InputStream和Reader进行了扩展,其中比较实用的有以下几个:
●AutoCloseInputStream
Proxy stream that closes and discards the underlying stream as soon as the end of input has been reached or when the stream is explicitly closed. Not even a reference to the underlying stream is kept after it has been closed, so any allocated in-memory buffers can be freed even if the client application still keeps a reference to the proxy stream
This class is typically used to release any resources related to an open stream as soon as possible even if the client application (by not explicitly closing the stream when no longer needed) or the underlying stream (by not releasing resources once the last byte has been read) do not do that.
这个输入流是一个底层输入流的代理,它能够在数据源的内容被完全读取到输入流后,后者当用户调用close()方法时,立即关闭底层的输入流。释放底层的资源(例如文件的句柄)。这个类的好处就是避免我们在代码中忘记关闭底层的输入流而造成文件处于一直打开的状态。
我们知道对于某些文件,只允许由一个进程打开。如果我们使用后忘记关闭那么该文件将处于一直“打开”的状态,其它进程无法读写。例如下面的例子:
new BufferedInputStream(new FileInputStream(FILE))
里面的FileInputStream(FILE)在打开后不能被显式关闭,这将导致可能出现的问题。如果我们使用了AutoCloseInputStream,那么当数据读取完毕后,底层的输入流会被自动关闭,迅速地释放资源。
new BufferedInputStream(new AutoClosedInputStream(new FileInputStream));
那么这个类是如何做到自动关闭的呢?来看看这个非常简单的类的代码吧
package org.apache.commons.io.input; import java.io.IOException; import java.io.InputStream; public class AutoCloseInputStream extends ProxyInputStream { public AutoCloseInputStream(InputStream in) { super(in); } public void close() throws IOException { in.close(); in = new ClosedInputStream(); } public int read() throws IOException { int n = in.read(); if (n == -1) { close(); } return n; } public int read(byte[] b) throws IOException { int n = in.read(b); if (n == -1) { close(); } return n; } public int read(byte[] b, int off, int len) throws IOException { int n = in.read(b, off, len); if (n == -1) { close(); } return n; } protected void finalize() throws Throwable { close(); super.finalize(); } } public class ClosedInputStream extends InputStream { /** * A singleton. */ public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream(); /** * Returns -1 to indicate that the stream is closed. * * @return always -1 */ public int read() { return -1; } }
可以看到这个类通过两个途径来保证底层的流能够被正确地关闭:
①每次调用read方法时,如果底层读到的是-1,立即关闭底层输入流。返回一个ClosedInputStream
②当这个类的对象被回收时,确保关闭底层的输入流
●TeeInputStream
InputStream proxy that transparently writes a copy of all bytes read from the proxied stream to a given OutputStream. The proxied input stream is closed when the close() method is called on this proxy. It is configurable whether the associated output stream will also closed.
可以看到这个类的作用是把输入流读入的数据原封不动地传递给输出流。这一点和JDK中提供的PipedInputStream的理念有些类似。在实际使用 中可以非常方便地做到像:将从远程URL读入的数据写到输出流,保存到文件之类的动作。当输入流被关闭时,输出流不一定被关闭。可以依然保持打开的状态。
下面是这个类的部分源码
public int read(byte[] bts, int st, int end) throws IOException { int n = super.read(bts, st, end); if (n != -1) { branch.write(bts, st, n); } return n; }
●CharSequenceReader
Reader implementation that can read from String, StringBuffer, StringBuilder or CharBuffer.
这个类可以看成是对StringReader的一个扩展,用于从内存中读取字符。
●NullReader
A functional, light weight Reader that emulates a reader of a specified size.
This implementation provides a light weight object for testing with an Reader where the contents don't matter.
One use case would be for testing the handling of large Reader as it can emulate that scenario without the overhead of actually processing large numbers of characters - significantly speeding up test execution times.
从上面的文字描述来看,这个类显然是用来做测试辅助的,它的目标对象是“对读入内容不关心”的需求。它并不传递真正的数据,而是模拟这个过程。来看看下面的源代码
/** * Read the specified number characters into an array. * * @param chars The character array to read into. * @param offset The offset to start reading characters into. * @param length The number of characters to read. * @return The number of characters read or <code>-1</code> * if the end of file has been reached and * <code>throwEofException</code> is set to <code>false</code>. * @throws EOFException if the end of file is reached and * <code>throwEofException</code> is set to <code>true</code>. * @throws IOException if trying to read past the end of file. */ public int read(char[] chars, int offset, int length) throws IOException { if (eof) { throw new IOException("Read after end of file"); } if (position == size) { return doEndOfFile(); } position += length; int returnLength = length; if (position > size) { returnLength = length - (int)(position - size); position = size; } processChars(chars, offset, returnLength); return returnLength; } /** * Return a character value for the <code>read()</code> method. * <p> * This implementation returns zero. * * @return This implementation always returns zero. */ protected int processChar() { // do nothing - overridable by subclass return 0; } /** * Process the characters for the <code>read(char[], offset, length)</code> * method. * <p> * This implementation leaves the character array unchanged. * * @param chars The character array * @param offset The offset to start at. * @param length The number of characters. */ protected void processChars(char[] chars, int offset, int length) { // do nothing - overridable by subclass }
知道它是怎么模拟的了吗?呵呵~~。原来它只是模拟计数的过程,根本不传递、处理、存储任何数据。数组始终都是空的。
【三】org.apache.commons.io.output包介绍
<!--[if !supportLineBreakNewLine]-->
和input包类似,output包也实现/继承了部分JDK IO包的类、接口。这里需要特别注意的有3个类,他们分别是:
①ByteArrayOutputStream
②FileWriterWithEncoding
③LockableFileWriter
●ByteArrayOutputStream
This class implements an output stream in which the data is written into a byte array. The buffer automatically grows as data is written to it.
The data can be retrieved using toByteArray() and toString().
Closing a ByteArrayOutputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.
This is an alternative implementation of the java.io.ByteArrayOutputStream class. The original implementation only allocates 32 bytes at the beginning. As this class is designed for heavy duty it starts at 1024 bytes. In contrast to the original it doesn't reallocate the whole memory block but allocates additional buffers. This way no buffers need to be garbage collected and the contents don't have to be copied to the new buffer. This class is designed to behave exactly like the original. The only exception is the deprecated toString(int) method that has been ignored.
从上面的文档中,我们看到Apache commons io的ByteArrayOutputString比起SUN自带的ByteArrayOutputStream更加高效,原因在于:
①缓冲区的初始化大小比原始的JDK自带的ByteArrayOutputStream要大很多(1024:32)
②缓冲区的大小可以无限增加。当缓冲不够时动态增加分配,而非清空后再重新封闭
③减少write方法的调用次数,一次性将多个一级缓冲数据写出。减少堆栈调用的时间
那么为什么这个类可以做到这些呢?来看看他的源码吧:
/** The list of buffers, which grows and never reduces. */ private List buffers = new ArrayList(); /** The current buffer. */ private byte[] currentBuffer; /** * Creates a new byte array output stream. The buffer capacity is * initially 1024 bytes, though its size increases if necessary. */ public ByteArrayOutputStream() { this(1024); }
而JDK自带的Buffer则只有简单的一个byte[]
/** * The buffer where data is stored. */ protected byte buf[]; /** * Creates a new byte array output stream. The buffer capacity is * initially 32 bytes, though its size increases if necessary. */ public ByteArrayOutputStream() { this(32); }
原来Apache commons 的io是采用了二级缓冲:首先一级缓冲是一个byte[],随着每次写出的数据不同而不同。二级缓冲则是一个无限扩充的ArrayList,每次从 byte[]中要写出的数据都会缓存到这里。当然效率上要高很多了。那么这个类是如何做到动态增加缓冲而不需要每次都回收已有的缓冲呢?
/** * Makes a new buffer available either by allocating * a new one or re-cycling an existing one. * * @param newcount the size of the buffer if one is created */ private void needNewBuffer(int newcount) { if (currentBufferIndex < buffers.size() - 1) { //Recycling old buffer filledBufferSum += currentBuffer.length; currentBufferIndex++; currentBuffer = getBuffer(currentBufferIndex); } else { //Creating new buffer int newBufferSize; if (currentBuffer == null) { newBufferSize = newcount; filledBufferSum = 0; } else { newBufferSize = Math.max( currentBuffer.length << 1, newcount - filledBufferSum); filledBufferSum += currentBuffer.length; } currentBufferIndex++; currentBuffer = new byte[newBufferSize]; buffers.add(currentBuffer); } }
在初始化的情况下,currentBuffer == null,于是第一个一级缓冲区byte[]的大小就是默认的1024或者用户指定的值。然后filledBufferSum、 currentBufferIndex分别进行初始化。创建第一个一级缓存区,添加到二级缓冲区buffers中。
当后续的缓冲请求到来后,根据剩下的缓冲大小和尚存的缓冲进行比较,然后选择较大的值作为缓冲扩展的大小。再次创建一个新的一级缓冲byte[],添加到二级缓冲中。
相比于JDK自带的方法,这个类多了一个write(InputStream in)的方法,看看下面的源代码
public synchronized int write(InputStream in) throws IOException { int readCount = 0; int inBufferPos = count - filledBufferSum; int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); while (n != -1) { readCount += n; inBufferPos += n; count += n; if (inBufferPos == currentBuffer.length) { needNewBuffer(currentBuffer.length); inBufferPos = 0; } n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); } return readCount; }
可以看到每次从InputStream读取当前一级缓冲剩余空间大小的字节,缓冲到剩下的空间。如果缓冲满了则继续分配新的一级缓冲。直至数据读完。对于写出到另外的输出流,则是:
public synchronized void writeTo(OutputStream out) throws IOException { int remaining = count; for (int i = 0; i < buffers.size(); i++) { byte[] buf = getBuffer(i); int c = Math.min(buf.length, remaining); out.write(buf, 0, c); remaining -= c; if (remaining == 0) { break; } } }
由于每次write的时候一次性地写出一级缓冲,而且是将二级缓冲全部写出,减少了调用的次数,所以提高了效率。
●FileWriterWithEncoding
从这个类的名称已经可以很清楚的知道它的作用了。在JDK自带的FileWriter中,是无法设置encoding的,这个类允许我们采用默认或者指定的encoding,以字符的形式写到文件。为什么这个类可以改变字符嗯?
原理很简单:无非使用了OutputStreamWriter。而且这个类并不是继承与FileWriter,而是直接继承于Writer。
OutputStream stream = null; Writer writer = null; try { stream = new FileOutputStream(file, append); if (encoding instanceof Charset) { writer = new OutputStreamWriter(stream, (Charset)encoding); } else if (encoding instanceof CharsetEncoder) { writer = new OutputStreamWriter(stream, (CharsetEncoder)encoding); } else { writer = new OutputStreamWriter(stream, (String)encoding); }
剩下的各种write方法,无非就是decorator模式而已。
●LockableFileWriter
使用“文件锁”而非“对象锁”来限制多线程环境下的写动作。这个类采用在JDK默认的系统临时目录下写文件:java.io.tmpdir属性。而且允许我们设置encoding。
/** * Constructs a LockableFileWriter with a file encoding. * * @param file the file to write to, not null * @param encoding the encoding to use, null means platform default * @param append true if content should be appended, false to overwrite * @param lockDir the directory in which the lock file should be held * @throws NullPointerException if the file is null * @throws IOException in case of an I/O error */ public LockableFileWriter(File file, String encoding, boolean append, String lockDir) throws IOException { super(); // init file to create/append file = file.getAbsoluteFile(); if (file.getParentFile() != null) { FileUtils.forceMkdir(file.getParentFile()); } if (file.isDirectory()) { throw new IOException("File specified is a directory"); } // init lock file if (lockDir == null) { lockDir = System.getProperty("java.io.tmpdir"); } File lockDirFile = new File(lockDir); FileUtils.forceMkdir(lockDirFile); testLockDir(lockDirFile); lockFile = new File(lockDirFile, file.getName() + LCK); // check if locked createLock(); // init wrapped writer out = initWriter(file, encoding, append); }
首先创建一个用于存放lock文件的目录,位于系统临时目录下。
接下来创建一个位于该目录下的名为xxxLCK的文件(锁文件)。
然后创建锁
最后则是初始化writer
显然我们关心的是如何创建这个锁,以及如何在写期间进行锁。首先来看创建锁的过程
private void createLock() throws IOException { synchronized (LockableFileWriter.class) { if (!lockFile.createNewFile()) { throw new IOException("Can't write file, lock " + lockFile.getAbsolutePath() + " exists"); } lockFile.deleteOnExit(); } }
注意这里的deleteOnExit()方法很重要,它告诉JVM:当JV退出是要删除该文件。否则磁盘上将有无数无用的临时锁文件。
下面的问题则是如何实现锁呢?呵呵~~。还是回到这个上面这个类的构造方法吧,我们看到在构造这个LockableFileWriter时,会调用 createLock()这个方法,而这个方法如果发现文件已经创建/被其它流引用时,会抛出一个IOException。于是创建不成功,也就无法继续 后续的write操作了。
那么如果第一个进程创建了锁之后就不释放,那么后续的进程岂不是无法写了,于是在这个类的close方法中有这样一句代码:
public void close() throws IOException { try { out.close(); } finally { lockFile.delete(); } }
每个进程在完成数据的写动作后,必须调用close()方法,于是锁文件被删除,锁被解除。相比于JDK中自带Writer使用的object锁 (synchronized(object)),这个方法确实要更加简便和高效。这个类当初就是被设计来替换掉原始的FileWriter的。
但切记:一定要在结尾处调用close()方法,否则无法解锁。而且这里没有AutoCloseOutputStream这样的类哦!
发表评论
-
高级Java程序员值得拥有的10本书
2015-05-04 07:24 814Java是时下最流行的编程语言之一。市面上也出现了适合初学者 ... -
深入理解java异常处理机制
2015-01-30 09:30 13321. 引子 try…catch…fi ... -
java 运行时参数设置
2015-01-07 09:13 870JVM的运行时参数: -Xms为执行单元内存的1/4, ... -
每个Java开发者都应该知道的5个JDK工具
2014-12-29 12:37 1145JDK是Java语言的软件开 ... -
使用双重锁判定可以大幅降低锁的征用
2014-12-29 12:30 752class ObjInstance { //单例 pri ... -
MAVEN Scope使用说明
2014-11-24 09:40 763在Maven的依赖管理中,经常会用到依赖的scope设置。这 ... -
Spring4 quartz job xml configuration
2014-11-11 09:46 14411. 定义job details public ... -
Add items into list in one line using guava
2014-11-10 10:54 726//@formatter:off fina ... -
配置动态读取(变化)文件 in Spring
2014-11-10 08:51 13271. 从环境变量中读取路径: <bean id=&q ... -
JAVA实现AES加密与解密
2014-11-04 15:34 663package com.eifesun.monitor.up ... -
Netty4.x分析
2014-07-31 11:06 1471官网定义: netty是一个异步、事件驱动的网络应用框架,用 ... -
Ways to sort lists of objects in Java based on multiple fields
2014-07-21 17:19 7751. the first way: Sorting wit ... -
how to parse a String to BigDecimal
2014-07-21 10:08 923private BigDecimal parsePrice( ... -
order list using google guava
2014-07-21 09:08 890Predicate<String> filter ... -
Java 读文件操作
2014-07-08 14:09 8931. only use java core, no exte ... -
怎样使Java 中测试按一定顺序执行
2014-03-10 11:27 1326@FixMethodOrder(MethodSorters. ... -
如何实现在当类初始化时,自动调动某个方法
2014-02-14 14:44 968有两种思路, 1. 将这个类实现为thread类 (or ... -
持续集成JenkinsAPI常见用法
2014-02-10 13:54 43jenkins(持续集成开源工具)提供了丰富的api接口,基 ... -
Sonar 安装与使用
2014-01-13 10:49 1735Sonar 是一个用于代码质量管理的开放平台。通过插件机制, ... -
源代码管理分析工具 Source Navigator的安装与使用
2014-01-13 09:51 1898Source-Navigator是原来redhat开发的一个 ...
相关推荐
Apache Commons IO 是一个Java库,专门用于处理输入/输出(I/O)操作。这个库提供了大量的实用工具类,使得在处理文件、流、过滤器、读写操作时更加方便。"commons-io-2.5.jar"是Apache Commons IO库的一个版本,...
### Apache Commons IO工具包知识点详解 #### 一、Apache Commons IO概述 Apache Commons IO是Apache Commons项目中的一个子项目,它提供了一系列与IO操作相关的工具类。这些工具类旨在简化和增强Java平台上的文件...
Apache Commons IO 是一个Java库,它提供了一系列与输入/输出流、文件操作、I/O utility类等相关的实用工具。这个库极大地简化了处理输入和输出流的复杂性,并且提供了许多方便的功能,使得在Java项目中进行IO操作...
Apache Commons FileUpload与Apache Commons IO是Java开发中两个非常重要的库,它们主要用于处理文件上传和I/O操作。这两个库在Web应用、数据处理以及文件管理等领域广泛应用。 Apache Commons FileUpload库是一个...
### Apache Commons IO 工具包使用 #### 一、Apache Commons IO 概述 Apache Commons IO 是 Apache Commons 项目下的一个子项目,主要用于提供一系列针对 Java IO 操作的实用工具类。这些工具类大大简化了文件和流...
Apache Commons IO 是一个Java开发库,它提供了许多实用的工具类来处理输入/输出操作。这个包中的类弥补了Java标准库在IO操作上的不足,为开发者提供了更强大的功能和便利性。`org.apache.commons.io`是这个库的核心...
Apache Commons IO是一个非常重要的Java库,它提供了大量的实用工具类,用于处理输入/输出操作。在标题中提到的"commons-io-2.11.0-bin.zip"是Apache Commons IO库的一个二进制发行版,版本号为2.11.0。这个压缩包...
Apache Commons IO 是一个Java库,它提供了一系列实用工具类来处理输入/输出操作。这个压缩包包含从0.1版本到2.4版本的所有Apache Commons IO的发布。这些版本跨越了多个年份,反映了该库在发展过程中的功能增强、...
项目中需要 org.apache.commons.io.IOUtils的可以下载此包,fileupload组件依赖的commons-io组件
apache-commons下全部官方源码和官方API文档,其中有: commons-beanutils-1.8.0 commons-codec commons-collections commons-dbcp commons-dbutils commons-fileupload commons-io commons-lang commons-lang3 ...
7. **IO**:Apache Commons IO 提供了一系列IO操作的辅助类,如文件复制、读写、流处理等,使得处理文件和I/O流变得更加简单和可靠。 8. **Net**:Apache Commons Net 提供了网络编程所需的工具类和协议实现,如FTP...
Apache Commons IO 是一个Java库,专注于提供各种I/O操作的实用工具类,这些操作包括文件、流、过滤器、读写、转换、检测等。在本案例中,我们讨论的是"commons-io-2.4"版本,这个版本包含了完整的Apache Commons IO...
Apache Commons IO 是一个Java库,专门用于处理输入/输出(I/O)操作。这个库提供了大量的实用工具类,简化了常见的文件、流、过滤器、读写操作等任务。"commons-io-2.11.0.rar"是Apache Commons IO库的版本2.11.0的...
Apache Commons IO库中的`org.apache.commons.io.FileUtils`类是一个非常实用的工具类,它提供了大量方便、高效的方法,用于处理文件系统操作。这个类在Java开发中被广泛使用,尤其是在处理大量的文件读写和管理任务...
《Apache Commons IO 2.6在Java开发中的应用详解》 Apache Commons IO是Apache软件基金会的一个开源项目,它提供了一系列实用的I/O操作工具,极大地简化了Java开发中与输入/输出相关的任务。其中,`commons-io-2.6....
《Apache Commons IO 2.3.jar:高效便捷的IO操作工具》 Apache Commons IO库是Java开发者必备的工具包之一,尤其是其中的commons-io-2.3.jar版本,它为处理输入/输出流、文件、字符集转换、线程安全的读写操作等...
Apache Commons IO 是一个Java库,专门用于处理输入/输出流操作。这个库包含了大量实用类和方法,使得在处理文件、字节流、字符流、过滤器和转换时更加便捷。"commons-io-2.7-bin.zip"是Apache Commons IO库的版本...
jar包分享,你懂的 com.springsource.org.apache.commons.io-1.4.0.jar
1. Apache Commons IO: 这个模块专注于输入/输出操作,如文件处理、流操作、数据转换等。它提供了一系列方便实用的类和方法,比如FileUtils用于文件操作,IOUtils用于流的读写和复制,以及EndianUtils用于处理字节序...
《Apache Commons IO 2.2:Java I/O操作的强大工具》 Apache Commons IO库是Java开发者广泛使用的工具库,主要用于处理各种I/O操作。在版本2.2中,这个库提供了一系列精心设计和优化的类和方法,极大地简化了与输入...