由于Android项目忙完,苦于学习方向迷失,决定开一个进度,学习解析commons-IO包,提高JAVA水平,学习JAVA IO部分。
?
废话不多说,进入正题。
?
1.
?
class="java" name="code">//----------------------------------------------------------------------- /** * Compares the contents of two files to determine if they are equal or not. * <p> * This method checks to see if the two files are different lengths * or if they point to the same file, before resorting to byte-by-byte * comparison of the contents. * <p> * Code origin: Avalon * * @param file1 the first file * @param file2 the second file * @return true if the content of the files are equal or they both don't * exist, false otherwise * @throws IOException in case of an I/O error */ public static boolean contentEquals(File file1, File file2) throws IOException { boolean file1Exists = file1.exists(); if (file1Exists != file2.exists()) { return false; } if (!file1Exists) { // two not existing files are equal return true; } if (file1.isDirectory() || file2.isDirectory()) { // don't want to compare directory contents throw new IOException("Can't compare directories, only files"); } if (file1.length() != file2.length()) { // lengths differ, cannot be equal return false; } if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { // same file return true; } InputStream input1 = null; InputStream input2 = null; try { input1 = new FileInputStream(file1); input2 = new FileInputStream(file2); return IOUtils.contentEquals(input1, input2); } finally { IOUtils.closeQuietly(input1); IOUtils.closeQuietly(input2); } }
这个函数用来比较两个file里面的文件是否相同。
?
比较策略:
1.判断是否有一个存在一个不存在(两个不存在也算相同)
2.判断两个是不是至少一个是目录(不能比较目录内容)
3.判断两个文件的长度是否相同,不同则返回false
4.应用File.getCanonicalFile()这个函数返回文件路径判断是不是指向同一个文件
5.最后才用inputstream导入两个文件,使用IOUtils.contentEquals(input1, input2)判断内容是否相等
?
2.
?
/** * Compares the contents of two files to determine if they are equal or not. * <p> * This method checks to see if the two files point to the same file, * before resorting to line-by-line comparison of the contents. * <p> * * @param file1 the first file * @param file2 the second file * @param charsetName the character encoding to be used. * May be null, in which case the platform default is used * @return true if the content of the files are equal or neither exists, * false otherwise * @throws IOException in case of an I/O error * @since 2.2 * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader) */ public static boolean contentEqualsIgnoreEOL(File file1, File file2, String charsetName) throws IOException { boolean file1Exists = file1.exists(); if (file1Exists != file2.exists()) { return false; } if (!file1Exists) { // two not existing files are equal return true; } if (file1.isDirectory() || file2.isDirectory()) { // don't want to compare directory contents throw new IOException("Can't compare directories, only files"); } if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { // same file return true; } Reader input1 = null; Reader input2 = null; try { if (charsetName == null) { input1 = new InputStreamReader(new FileInputStream(file1)); input2 = new InputStreamReader(new FileInputStream(file2)); } else { input1 = new InputStreamReader(new FileInputStream(file1), charsetName); input2 = new InputStreamReader(new FileInputStream(file2), charsetName); } return IOUtils.contentEqualsIgnoreEOL(input1, input2); } finally { IOUtils.closeQuietly(input1); IOUtils.closeQuietly(input2); } }
本函数和上一条基本相同,区别在于:
?
?
Reader input1 = null; Reader input2 = null; try { if (charsetName == null) { input1 = new InputStreamReader(new FileInputStream(file1)); input2 = new InputStreamReader(new FileInputStream(file2)); } else { input1 = new InputStreamReader(new FileInputStream(file1), charsetName); input2 = new InputStreamReader(new FileInputStream(file2), charsetName); } return IOUtils.contentEqualsIgnoreEOL(input1, input2); } finally { IOUtils.closeQuietly(input1); IOUtils.closeQuietly(input2); }
这里使用了charsetName,用以获取编码后的字符流
?
*学习:
InputStreamReader的创建(使用charsetName参数编码FileInputStream获取的字节)
?
?
?
?
3.
?
public static File toFile(URL url) { if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) { return null; } else { String filename = url.getFile().replace('/', File.separatorChar); filename = decodeUrl(filename); return new File(filename); } }
一个用于把file协议的url转换为File类型的函数
?
?
4.
?
static String decodeUrl(String url) { String decoded = url; if (url != null && url.indexOf('%') >= 0) { int n = url.length(); StringBuffer buffer = new StringBuffer(); ByteBuffer bytes = ByteBuffer.allocate(n); for (int i = 0; i < n;) { if (url.charAt(i) == '%') { try { do { byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16); bytes.put(octet); i += 3; } while (i < n && url.charAt(i) == '%'); continue; } catch (RuntimeException e) { // malformed percent-encoded octet, fall through and // append characters literally } finally { if (bytes.position() > 0) { bytes.flip(); buffer.append(UTF8.decode(bytes).toString()); bytes.clear(); } } } buffer.append(url.charAt(i++)); } decoded = buffer.toString(); } return decoded; }
转换URL出现问题时的优化处理
?
(存疑)
?
?
5.
?
public static File[] toFiles(URL[] urls) { if (urls == null || urls.length == 0) { return EMPTY_FILE_ARRAY; } File[] files = new File[urls.length]; for (int i = 0; i < urls.length; i++) { URL url = urls[i]; if (url != null) { if (url.getProtocol().equals("file") == false) { throw new IllegalArgumentException( "URL could not be converted to a File: " + url); } files[i] = toFile(url); } } return files; }
Converts each of an array of URL
to a File
.
?
刚才函数toFile()的数组版本
?
6.
?
public static URL[] toURLs(File[] files) throws IOException { URL[] urls = new URL[files.length]; for (int i = 0; i < urls.length; i++) { urls[i] = files[i].toURI().toURL(); } return urls; }
Converts each of an array of File
to a URL
.
?
?
7.
?
public static void copyFileToDirectory(File srcFile, File destDir) throws IOException { copyFileToDirectory(srcFile, destDir, true); }
Copies a file to a directory preserving the file date.
?
?
8.
?
public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException { if (destDir == null) { throw new NullPointerException("Destination must not be null"); } if (destDir.exists() && destDir.isDirectory() == false) { throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory"); } File destFile = new File(destDir, srcFile.getName()); copyFile(srcFile, destFile, preserveFileDate); }
刚才函数7的完整版本:
?
1.确保目标地址不是空的
2.确保目标地址存在,并且不是文件
3.对源文件和目标文件的保护在copyFile里做了,所以这里只做对目标目录的保护。
?
?
9.
?
public static void copyFile(File srcFile, File destFile) throws IOException { copyFile(srcFile, destFile, true); }
?
?
包装函数,重载默认保存date
?
10.
?
public static void copyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException { if (srcFile == null) { throw new NullPointerException("Source must not be null"); } if (destFile == null) { throw new NullPointerException("Destination must not be null"); } if (srcFile.exists() == false) { throw new FileNotFoundException("Source '" + srcFile + "' does not exist"); } if (srcFile.isDirectory()) { throw new IOException("Source '" + srcFile + "' exists but is a directory"); } if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) { throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same"); } File parentFile = destFile.getParentFile(); if (parentFile != null) { if (!parentFile.mkdirs() && !parentFile.isDirectory()) { throw new IOException("Destination '" + parentFile + "' directory cannot be created"); } } if (destFile.exists() && destFile.canWrite() == false) { throw new IOException("Destination '" + destFile + "' exists but is read-only"); } doCopyFile(srcFile, destFile, preserveFileDate); }
策略学习:
?
目标文件和源文件的保护监测
?
11.
?
public static long copyFile(File input, OutputStream output) throws IOException { final FileInputStream fis = new FileInputStream(input); try { return IOUtils.copyLarge(fis, output); } finally { fis.close(); } }
从一个input文件中拷贝bytes进入output输出流,注意:
?
IOUtils.copyLarge(fis, output)这个方法内部使用了buffer,所以不需要使用BufferedInputStream
?
12.
?
private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException { if (destFile.exists() && destFile.isDirectory()) { throw new IOException("Destination '" + destFile + "' exists but is a directory"); } FileInputStream fis = null; FileOutputStream fos = null; FileChannel input = null; FileChannel output = null; try { fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); input = fis.getChannel(); output = fos.getChannel(); long size = input.size(); long pos = 0; long count = 0; while (pos < size) { count = size - pos > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : size - pos; pos += output.transferFrom(input, pos, count); } } finally { IOUtils.closeQuietly(output); IOUtils.closeQuietly(fos); IOUtils.closeQuietly(input); IOUtils.closeQuietly(fis); } if (srcFile.length() != destFile.length()) { throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "'"); } if (preserveFileDate) { destFile.setLastModified(srcFile.lastModified()); } }
使用nio中的FileChannel进行复制(传输文件内容),调用IOUtils.closeQuietly()关闭filechannel和I/Ostream
?
最后用文件的length长度监测是否传输成功
?
?
16. publicstaticvoidcopyDirectory(File srcDir, File destDir, FileFilter filter,booleanpreserveFileDate)throwsIOException { if(srcDir ==null) { thrownewNullPointerException("Source must not be null"); } if(destDir ==null) { thrownewNullPointerException("Destination must not be null"); } if(srcDir.exists() ==false) { thrownewFileNotFoundException("Source '"+ srcDir +"' does not exist"); } if(srcDir.isDirectory() ==false) { thrownewIOException("Source '"+ srcDir +"' exists but is not a directory"); } if(srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) { thrownewIOException("Source '"+ srcDir +"' and destination '"+ destDir +"' are the same"); } ? // Cater for destination being directory within the source directory (see IO-141) List<String> exclusionList =null; if(destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) { File[] srcFiles = filter ==null? srcDir.listFiles() : srcDir.listFiles(filter); if(srcFiles !=null&& srcFiles.length> 0) { exclusionList =newArrayList<String>(srcFiles.length); for(File srcFile : srcFiles) { File copiedFile =newFile(destDir, srcFile.getName()); exclusionList.add(copiedFile.getCanonicalPath()); } } } doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList); } ? ? ? 这个函数加入了一个filter对复制操作的file加以过滤 ? 注意:这里有一个假如destDir是srcDir的子目录的附加操作 // Cater for destination being directory within the source directory (see IO-141) List<String> exclusionList =null; if(destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) { File[] srcFiles = filter ==null? srcDir.listFiles() : srcDir.listFiles(filter); if(srcFiles !=null&& srcFiles.length> 0) { exclusionList =newArrayList<String>(srcFiles.length); for(File srcFile : srcFiles) { File copiedFile =newFile(destDir, srcFile.getName()); exclusionList.add(copiedFile.getCanonicalPath()); } } } ? exclusionList是要排除的文件路径String列表(因为本来就在desDir里面),要作为参数传入下一个docopy()方法中 ? ? 17. privatestaticvoiddoCopyDirectory(FilesrcDir, File destDir, FileFilter filter, booleanpreserveFileDate, List<String> exclusionList)throwsIOException { // recurse File[] srcFiles = filter ==null?srcDir.listFiles() :srcDir.listFiles(filter); if(srcFiles ==null) {// null if abstract pathname does not denote a directory, or if an I/O error occurs thrownewIOException("Failed to list contents of "+srcDir); } if(destDir.exists()) { if(destDir.isDirectory() ==false) { thrownewIOException("Destination '"+ destDir +"' exists but is not a directory"); } }else{ if(!destDir.mkdirs() && !destDir.isDirectory()) { thrownewIOException("Destination '"+ destDir +"' directory cannot be created"); } } if(destDir.canWrite() ==false) { thrownewIOException("Destination '"+ destDir +"' cannot be written to"); } for(File srcFile : srcFiles) { File dstFile =newFile(destDir, srcFile.getName()); if(exclusionList ==null|| !exclusionList.contains(srcFile.getCanonicalPath())) { if(srcFile.isDirectory()) { doCopyDirectory(srcFile, dstFile, filter, preserveFileDate, exclusionList); }else{ doCopyFile(srcFile, dstFile, preserveFileDate); } } } ? // Do this last, as the above has probably affected directory metadata if(preserveFileDate) { destDir.setLastModified(srcDir.lastModified()); } } ? ? 注意: 1.递归调用,反复打开子目录复制文件 2.排除列表的操作 ? ? 20. publicstaticvoidcopyInputStreamToFile(InputStream source, File destination)throwsIOException { try{ FileOutputStream output =openOutputStream(destination); try{ IOUtils.copy(source, output); output.close();// don't swallow close Exception if copy completes normally }finally{ IOUtils.closeQuietly(output); } }finally{ IOUtils.closeQuietly(source); } } ? 使用IOUtils.copy()函数复制source流到output流(目标文件输出流) ? ? 21. publicstaticvoiddeleteDirectory(File directory)throwsIOException { if(!directory.exists()) { return; } ? if(!isSymlink(directory)) { cleanDirectory(directory); } ? if(!directory.delete()) { String message = "Unable to delete directory "+ directory +"."; thrownewIOException(message); } } ? ? isSymlink(directory)貌似和windows没关系??暂时存疑 调用cleanDirectory清空目录,然后删除目录本身 ? ? 22. publicstaticbooleandeleteQuietly(File file) { if(file ==null) { returnfalse; } try{ if(file.isDirectory()) { cleanDirectory(file); } }catch(Exception ignored) { } ? try{ returnfile.delete(); }catch(Exception ignored) { returnfalse; } } ? 本身Doc的描述:Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories.
The difference between File.delete() and this method are:
?
?
?