All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.io.FileUtil Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.io;

import static com.feilong.core.bean.ConvertUtil.toMapUseEntrys;
import static com.feilong.core.lang.StringUtil.EMPTY;
import static com.feilong.io.entity.FileType.DIRECTORY;
import static com.feilong.io.entity.FileType.FILE;
import static com.feilong.io.entity.FileWriteMode.APPEND;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.core.Validate;
import com.feilong.core.bean.ConvertUtil;
import com.feilong.io.entity.FileWriteMode;
import com.feilong.lib.io.FileUtils;
import com.feilong.lib.lang3.tuple.Pair;

/**
 * {@link File}文件操作.
 * 
 * 

File的几个属性:

* *
*
    *
  • {@link File#getAbsolutePath()} 得到的是全路径
  • *
  • {@link File#getPath()} 得到的是构造file的时候的路径
  • *
  • {@link File#getCanonicalPath()} 可以看到CanonicalPath不但是全路径,而且把..或者.这样的符号解析出来.
  • *
*
* * *

关于大小:

* *
*
    *
  • {@link FileUtils#ONE_KB} 1024
  • *
  • {@link FileUtils#ONE_MB} 1024 * 1024 1048576
  • *
  • {@link FileUtils#ONE_GB} 1024 * 1024 * 1024 1073741824 *

    * 注意,{@link Integer#MAX_VALUE}=2147483647 是2G大小 *

    *
*
* * @author feilong * @see java.io.File * @see com.feilong.lib.io.FilenameUtils * @see com.feilong.lib.io.FileUtils * @since 1.0.0 */ @SuppressWarnings("squid:S1192") //String literals should not be duplicated public final class FileUtil{ /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(FileUtil.class); //--------------------------------------------------------------- /** * The number of bytes in a kilobyte. */ public static final Long ONE_KB = 1024L; /** * The number of bytes in a megabyte. */ public static final long ONE_MB = ONE_KB * ONE_KB; /** * The number of bytes in a gigabyte. */ public static final long ONE_GB = ONE_KB * ONE_MB; /** * The number of bytes in a terabyte. */ public static final long ONE_TB = ONE_KB * ONE_GB; //--------------------------------------------------------------- /** 默认缓冲大小 10k {@value}. */ public static final int DEFAULT_BUFFER_LENGTH = (int) (10 * ONE_KB); /** 除数和单位的map,必须是有顺序的 从大到小. */ private static final Map DIVISOR_AND_UNIT_MAP = toMapUseEntrys( Pair.of(ONE_TB, "TB"), //(Terabyte,太字节,或百万兆字节)=1024GB,其中1024=2^10 ( 2 的10次方)。 Pair.of(ONE_GB, "GB"), //(Gigabyte,吉字节,又称“千兆”)=1024MB, Pair.of(ONE_MB, "MB"), //(Megabyte,兆字节,简称“兆”)=1024KB, Pair.of(ONE_KB, "KB")); //(Kilobyte 千字节)=1024B //--------------------------------------------------------------- /** Don't let anyone instantiate this class. */ private FileUtil(){ //AssertionError不是必须的. 但它可以避免不小心在类的内部调用构造器. 保证该类在任何情况下都不会被实例化. //see 《Effective Java》 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } //--------------------------------------------------------------- /** * 将文件 filePath 转成 byte[] bytes. * * @param filePath * 文件路径 * @return 如果 fileName 是null,抛出 {@link NullPointerException}
* 如果 fileName 是blank,抛出 {@link IllegalArgumentException}
* @see #toByteArray(File) * @see java.io.ByteArrayOutputStream#toByteArray() * @since 1.2.1 */ public static byte[] toByteArray(String filePath){ Validate.notBlank(filePath, "filePath can't be blank!"); File file = new File(filePath); return toByteArray(file); } //--------------------------------------------------------------- /** * 将文件转成 byte[] bytes. * * @param file * file * @return 如果 file 是null,抛出 {@link NullPointerException}
* @see #getFileInputStream(File) * @see java.io.ByteArrayOutputStream#toByteArray() * @see com.feilong.lib.io.FileUtils#readFileToByteArray(File) * @see com.feilong.lib.io.IOUtils#toByteArray(InputStream, int) */ public static byte[] toByteArray(File file){ Validate.notNull(file, "file can't be null!"); //--------------------------------------------------------------- try{ return FileUtils.readFileToByteArray(file); }catch (IOException e){ throw new UncheckedIOException(e); } } //--------------------------------------------------------------- /** * 获得 {@link java.io.FileOutputStream FileOutputStream} 文件输出流. * *

* 该方法输出是使用 覆盖模式, 如果要使用追加模式, 请调用 {@link #getFileOutputStream(String, FileWriteMode)} *

* *

* {@link java.io.FileOutputStream FileOutputStream} 用于写入诸如图像数据之类的原始字节的流. *

* *

* 如果要写入字符流,请考虑使用 {@link java.io.FileWriter}. *

* * @param filePath * 文件路径 * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* @see java.io.FileOutputStream#FileOutputStream(String) * @see #getFileOutputStream(String, boolean) */ public static FileOutputStream getFileOutputStream(String filePath){ Validate.notBlank(filePath, "filePath can't be blank!"); return getFileOutputStream(filePath, false);//默认 append 是 false } /** * 获得 {@link java.io.FileOutputStream FileOutputStream} 文件输出流. * *

* {@link java.io.FileOutputStream FileOutputStream} 用于写入诸如图像数据之类的原始字节的流. *

* *

* 如果要写入字符流,请考虑使用 {@link java.io.FileWriter}. *

* * @param filePath * the file path * @param fileWriteMode * the file write mode * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* 如果 fileWriteMode 是null,抛出 {@link NullPointerException}
* @see #getFileOutputStream(String, boolean) * @since 1.2.0 */ public static FileOutputStream getFileOutputStream(String filePath,FileWriteMode fileWriteMode){ Validate.notBlank(filePath, "filePath can't be blank!"); Validate.notNull(fileWriteMode, "fileWriteMode can't be null!"); //--------------------------------------------------------------- boolean append = fileWriteMode == APPEND; return getFileOutputStream(filePath, append); } //--------------------------------------------------------------- /** * 获得 {@link java.io.FileOutputStream FileOutputStream} 文件输出流. * *

* {@link java.io.FileOutputStream FileOutputStream} 用于写入诸如图像数据之类的原始字节的流. *

* *

* 如果要写入字符流,请考虑使用 {@link java.io.FileWriter}. *

* * @param filePath * the file path * @param append * if {@code true}, then bytes will be added to the end of the file rather than overwriting * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* @see java.io.FileOutputStream#FileOutputStream(String, boolean) * @see com.feilong.lib.io.FileUtils#openOutputStream(File, boolean) * @since 1.2.0 */ //默认 Access Modifiers 权限修饰符 static FileOutputStream getFileOutputStream(String filePath,boolean append){ Validate.notBlank(filePath, "filePath can't be blank!"); return getFileOutputStream(new File(filePath), append); } /** * 获得 {@link java.io.FileOutputStream} 文件输出流 (或其他文件写入对象)打开文件进行写入 . * *

* {@link java.io.FileOutputStream} 用于写入诸如图像数据之类的原始字节的流.
* 如果要写入字符流,请考虑使用 {@link java.io.FileWriter}. *

* * @param file * the file * @param append * if {@code true}, then bytes will be added to the end of the file rather than overwriting * @return the file output stream * @see com.feilong.lib.io.FileUtils#openOutputStream(File, boolean) * @since 1.4.0 */ //默认 Access Modifiers 权限修饰符 static FileOutputStream getFileOutputStream(File file,boolean append){ Validate.notNull(file, "file can't be null!"); //--------------------------------------------------------------- try{ return FileUtils.openOutputStream(file, append); }catch (IOException e){ throw new UncheckedIOException("file:[" + file + "],append:" + append, e); } } //--------------------------------------------------------------- /** * 从文件系统中的文件 filePath 中获得输入字节. * *

* {@link java.io.FileInputStream} 用于读取诸如图像数据之类的原始字节流. *

* *

* 要读取字符流,请考虑使用 {@link java.io.FileReader} *

* * @param filePath * 该文件通过文件系统中的路径名 filePath 指定. * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* @see #getFileInputStream(File) */ public static FileInputStream getFileInputStream(String filePath){ Validate.notBlank(filePath, "filePath can't be blank!"); return getFileInputStream(new File(filePath)); } /** * 从文件系统中的文件 file 中获得输入字节. * *

* {@link java.io.FileInputStream} 用于读取诸如图像数据之类的原始字节流. *

* *

* 要读取字符流,请考虑使用 {@link java.io.FileReader} *

* *

* 如果指定文件不存在;或者它是一个目录,而不是一个常规文件;亦或因为其他某些原因而无法打开进行读取,则抛出 {@link FileNotFoundException} *

* * @param file * 为了进行读取而打开的文件. * @return 如果 file 是null,抛出 {@link NullPointerException}
* @see com.feilong.lib.io.FileUtils#openInputStream(File) */ public static FileInputStream getFileInputStream(File file){ Validate.notNull(file, "file can't be null!"); //--------------------------------------------------------------- try{ return FileUtils.openInputStream(file); }catch (IOException e){ throw new UncheckedIOException(e); } } //--------------------------------------------------------------- /** * 判断一个目录是否是空目录 (判断的原则:里面没有文件). * * @param directory * 指定一个存在的文件夹 * @return *
    *
  • 如果directory isNullOrEmpty,抛出 {@link IllegalArgumentException}
  • *
  • 如果directory don't exists,抛出 {@link IllegalArgumentException}
  • *
  • 如果directory is not Directory,抛出 {@link IllegalArgumentException}
  • *
  • return file.list() ==0
  • *
* @see com.feilong.lib.io.FileUtils#sizeOf(File) * @see com.feilong.lib.io.FileUtils#sizeOfDirectory(File) */ public static boolean isEmptyDirectory(String directory){ Validate.notBlank(directory, "directory can't be null/empty!"); //--------------------------------------------------------------- File file = new File(directory); Validate.isTrue(file.exists(), "directory file " + directory + " don't exists!"); Validate.isTrue(file.isDirectory(), "directory file " + directory + " is not Directory!"); //--------------------------------------------------------------- // Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname. // 如果此抽象路径名不表示一个目录,那么此方法将返回 null // ubuntu 已经 测试ok File[] listFiles = file.listFiles(); int fileListLength = listFiles.length; if (LOGGER.isDebugEnabled()){ LOGGER.debug("file :[{}] list length:[{}]", directory, fileListLength); for (File tempFile : listFiles){ LOGGER.debug("[{}] [{}]", tempFile.getName(), tempFile.isDirectory() ? DIRECTORY : FILE); } } return 0 == fileListLength; } // [start] 文件夹操作(createDirectory/deleteFileOrDirectory/deleteFileOrDirectory) /** * 创建文件夹,by文件路径 filePath ,支持级联创建. * *

注意:

* *
    *
  1. 此处参数是文件路径,如果需要传递文件夹路径自动创建文件夹,那么请调用 {@link #createDirectory(String)}
  2. *
  3. 对于不存在的文件夹/文件夹: "E:\\test\\1\\2011-07-07" 这么一个路径,没有办法自动区别到底你是要创建文件还是文件夹
  4. *
  5. {@link File#isDirectory()} 这个方法,必须文件存在 才能判断
  6. *
  7. 如果文件所属的文件夹已经存在,那么仅会记录debug level的日志
  8. *
* *

代码流程:

* *
*
    *
  1. 如果 filePath 是null,抛出 {@link NullPointerException}
  2. *
  3. 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
  4. *
  5. {@link #getParent(String) getParent}(filePath)
  6. *
  7. {@link #createDirectory(String) createDirectory}(directory)
  8. *
*
* * @param filePath * 文件路径 * @see #getParent(String) * @see #createDirectory(String) * @since 1.2.0 */ public static void createDirectoryByFilePath(String filePath){ Validate.notBlank(filePath, "filePath can't be null/empty!"); //--------------------------------------------------------------- String directory = getParent(filePath); createDirectory(directory); } //--------------------------------------------------------------- /** * 创建文件夹,支持级联创建. * *

注意:

* *
    *
  1. 此处参数是文件夹,如果需要传递文件路径自动创建父文件夹,那么请调用 {@link #createDirectoryByFilePath(String)}
  2. *
  3. 对于不存在的文件夹/文件夹: "E:\\test\\1\\2011-07-07" 这么一个路径, 没有办法自动区别到底你是要创建文件还是文件夹
  4. *
  5. {@link File#isDirectory()} 这个方法,必须文件存在才能判断
  6. *
  7. 如果文件夹已经存在,那么仅会记录trace level的日志
  8. *
* *

代码流程:

* *
*
    *
  1. 如果 directory 是null,抛出 {@link NullPointerException}
  2. *
  3. 如果 directory 是blank,抛出 {@link IllegalArgumentException}
  4. * *
  5. {@code if directory exists---->log debug and return}
  6. *
  7. {@link java.io.File#mkdirs()}
  8. *
  9. {@code if mkdirs's result is false ---> return IllegalArgumentException}
  10. *
  11. {@code if mkdirs's result is true ---> log debug}
  12. *
*
* * @param directory * 文件夹路径 * @see #createDirectoryByFilePath(String) */ public static void createDirectory(String directory){ Validate.notBlank(directory, "directory can't be null/empty!"); //--------------------------------------------------------------- File directoryFile = new File(directory); boolean isExists = directoryFile.exists(); //---------------do with 存在------------------------------------------------ if (isExists){//存在 LOGGER.trace("directory:[{}] exists,don't need mkdirs,nothing to do~", directoryFile); return; } //----------------do with 不存在----------------------------------------------- String absolutePath = directoryFile.getAbsolutePath(); // mkdir 如果 parent 目录不存在 会返回false 不会报错 boolean flag = directoryFile.mkdirs(); // 级联创建 父级文件夹 Validate.isTrue(flag, "could't create directory:[%s]", absolutePath); //创建成功 记录下日志 LOGGER.debug("success mkdirs:[{}]~~", absolutePath); } //--------------------------------------------------------------- /** * 删除文件或者文件夹,如果是文件夹 ,递归深层次 删除. * *

* Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. *

* *

difference between {@link File#delete()} and current method:

* *
*
    *
  • A directory to be deleted does not have to be empty.
  • *
  • No exceptions are thrown when a file or directory cannot be deleted.
  • *
*
* * @param filePath * 文件或者文件夹路径 * @return 如果 fileName 是null,抛出 {@link NullPointerException}
* 如果 fileName 是blank,抛出 {@link IllegalArgumentException}
* {@code true} if the file or directory was deleted, otherwise {@code false} * @see #deleteFileOrDirectory(File) */ public static boolean deleteFileOrDirectory(String filePath){ Validate.notBlank(filePath, "filePath can't be blank!"); return deleteFileOrDirectory(new File(filePath)); } /** * 删除文件或者文件夹,如果是文件夹 ,递归深层次删除. * *

* Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. *

* *

difference between {@link File#delete()} and current method:

* *
*
    *
  • A directory to be deleted does not have to be empty.
  • *
  • No exceptions are thrown when a file or directory cannot be deleted.
  • *
*
* * @param file * file or directory to delete, can be {@code null} * @return 如果 file 是null,抛出 {@link NullPointerException}
* {@code true} if the file or directory was deleted, otherwise {@code false} * @see com.feilong.lib.io.FileUtils#deleteQuietly(File) */ public static boolean deleteFileOrDirectory(File file){ Validate.notNull(file, "file can't be null!"); return FileUtils.deleteQuietly(file); } // [end] //--------------------------------------------------------------- /** * 返回此路径 filePath 父目录的路径名字符串. * *

说明:

*
*
    *
  1. filePath 可以不存在
  2. *
  3. filePath 可以是文件,也可以是文件夹
  4. *
*
* *

示例:

* *
* *
     * FileUtil.getParent("/");// null
     * FileUtil.getParent("/Users/feilong/feilong/logs/createDirectoryByFilePath");// /Users/feilong/feilong/logs
     * 
     * // 不存在
     * FileUtil.getParent("/Users/feilong/feilong/logs/getParent/getParent");// /Users/feilong/feilong/logs/getParent
     * 
     * // 文件
     * FileUtil.getParent("/Users/feilong/feilong/logs/1.txt");// /Users/feilong/feilong/logs
     * 
* *
* * @param filePath * the path * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* * 如果此路径名没有指定父目录,则返回 null. * @see java.io.File#getParent() */ public static String getParent(String filePath){ Validate.notBlank(filePath, "filePath can't be null/empty!"); //--------------------------------------------------------------- File file = new File(filePath); return file.getParent(); } /** * 判断文件 filePath 是否存在. * * @param filePath * the file path * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* 如果文件存在,返回true * @see java.io.File#exists() */ public static boolean isExistFile(String filePath){ Validate.notBlank(filePath, "filePath can't be blank!"); File file = new File(filePath); return file.exists(); } /** * 判断文件 filePath 不存在. * * @param filePath * the file path * @return 如果 filePath 是null,抛出 {@link NullPointerException}
* 如果 filePath 是blank,抛出 {@link IllegalArgumentException}
* 如果文件不存在,返回true * @see com.feilong.io.FileUtil#isExistFile(String) * @since 1.0.3 */ public static boolean isNotExistFile(String filePath){ Validate.notBlank(filePath, "filePath can't be blank!"); return !isExistFile(filePath); } //--------------------------------------------------------------- /** * 返回指定的文件或目录 file 的大小, 取得文件大小(单位字节). * *

* 返回指定的文件或目录的大小。
* 如果提供的文件是一个常规文件,那么文件的长度将被返回。
* 如果参数是一个目录,那么目录的大小是递归计算的。 *

* * @param file * 文件 * @return 如果 file 是null,抛出 {@link NullPointerException}
* 此抽象路径名表示的文件的长度,以字节为单位;
* 如果文件不存在,则返回 0L.
* 对于表示特定于系统的实体(比如设备或管道)的路径名,某些操作系统可能返回 0L. * @see File#length() * @see com.feilong.lib.io.FileUtils#sizeOf(File) */ public static long getFileSize(File file){ Validate.notNull(file, "file can't be null!"); return FileUtils.sizeOf(file); } //--------------------------------------------------------------- /** * 获得文件 file 格式化大小. * *

* 比如文件3834字节,格式化大小 3.74KB
* 比如文件36830335 字节, 格式化大小:35.12MB
* 比如文件2613122669 字节, 格式化大小 : 2.43GB
*

* *

* 目前支持单位有TB GB MB KB以及最小单位 Bytes *

* * @param file * the file * @return 如果 file 是null,抛出 {@link NullPointerException}
* @see #getFileSize(File) * @see com.feilong.io.FileUtil#formatSize(long) * @see "com.feilong.lib.io.FileUtils#byteCountToDisplaySize(long)" * @since 1.0.7 */ public static String getFileFormatSize(File file){ Validate.notNull(file, "file can't be null!"); long fileSize = getFileSize(file); return formatSize(fileSize); } /** * 文件大小 fileSize 格式化. * *

* 目前支持单位有TB GB MB KB以及最小单位 Bytes *

* *

示例:

* *
* *
     * 
     * LOGGER.info(FileUtil.formatSize(8981528));
     * LOGGER.info(org.apache.commons.io.FileUtils.byteCountToDisplaySize(8981528));
     * 
     * 
* * 返回: * *
     * 00:06 INFO (FileUtilTest.java:204) [formatFileSize()] 8.56MB
     * 00:07 INFO (FileUtilTest.java:205) [formatFileSize()] 8 MB
     * 
* *
* *

* Common-io 2.4{@link com.feilong.lib.io.FileUtils#byteCountToDisplaySize(long)}有缺点,显示的是整数GB 不带小数(比如1.99G 显示为1G),apache 论坛上争议比较大 *

* * @param fileSize * 文件大小 单位byte * @return 如果 {@code fileSize < 0} ,抛出 {@link IllegalArgumentException}
* 如果 {@code fileSize < } {@link FileUtils#ONE_KB},直接返回 fileSize + "Bytes"
* @see com.feilong.lib.io.FileUtils#ONE_TB * @see com.feilong.lib.io.FileUtils#ONE_GB * @see com.feilong.lib.io.FileUtils#ONE_MB * @see com.feilong.lib.io.FileUtils#ONE_KB */ public static String formatSize(long fileSize){ Validate.isTrue(fileSize >= 0, "fileSize :[%s] must >=0"); if (fileSize < ONE_KB){ return fileSize + "Bytes"; } //--------------------------------------------------------------- for (Map.Entry entry : DIVISOR_AND_UNIT_MAP.entrySet()){ Long divisor = entry.getKey(); String unit = entry.getValue(); if (fileSize >= divisor){ //100的作用是 保持2位小数 long remainder = 100 * (fileSize % divisor) / divisor; // 除完之后的余数 return fileSize / divisor + (0 == remainder ? EMPTY : ("." + remainder)) + unit; } } //--------------------------------------------------------------- throw new UnsupportedOperationException("fileSize:[" + fileSize + "] not support!");//理论上不会到这里 } //--------------------------------------------------------------- /** * 将 filePathList 转成 {@link URL} 数组. * * @param filePathList * the paths * @return 如果 filePathList 是null,抛出 {@link NullPointerException}
* 如果 filePathList 是empty,抛出 {@link IllegalArgumentException}
* @see #toURLs(String...) * @since 1.4.0 */ public static URL[] toURLs(List filePathList){ Validate.notEmpty(filePathList, "filePathList can't be null/empty!"); String[] filePaths = ConvertUtil.toArray(filePathList, String.class); return toURLs(filePaths); } //--------------------------------------------------------------- /** * 将 filePaths 转成 {@link URL} 数组. * * @param filePaths * the file paths * @return 如果 filePaths 是null,抛出 {@link NullPointerException}
* 如果 filePaths 是empty,抛出 {@link IllegalArgumentException}
* @see com.feilong.core.bean.ConvertUtil#toArray(String[], Class) * @see com.feilong.lib.io.FileUtils#toURLs(File[]) * @since 1.4.0 */ public static URL[] toURLs(String...filePaths){ Validate.notEmpty(filePaths, "filePaths can't be null/empty!"); //--------------------------------------------------------------- File[] files = ConvertUtil.toArray(filePaths, File.class); try{ return FileUtils.toURLs(files); }catch (IOException e){ throw new UncheckedIOException(e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy