Java文件操作之复制、压缩、解压
一、文件复制
1、通过文件流Stream对文件进行复制
这种方式的文件复制主要是通过InputStream读取文件流,再将读取的文件流数据写入到新创建的文件中。
/**
* @Description 文件复制(使用Stream流操作)
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/24 15:15
*/
public static void copyFileByStream(File srcFile, File tarFile) {
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(srcFile);
output = new FileOutputStream(tarFile);
byte[] bytes = new byte[byteLen];
//字节长度
int byteLen = 0;
while (true) {
//字节为空时,跳出循环
if (!((byteLen = input.read(bytes)) > 0)) {
break;
}
//向目标文件写入流数据
output.write(bytes, 0, byteLen);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (output != null) {
IOUtils.closeQuietly(output);
}
if (input != null) {
IOUtils.closeQuietly(input);
}
}
}
2、通过FileChannel对文件进行复制
FileChannel操作文件流时使用的是ByteBuffer缓存区,而InputStream/OutputStream文件操作使用的是byte[]数组,由于FileChannel使用的是ByteBuffer缓存区,所以性能上应该是优于InputStream/OutputStream的。
/**
* @Description 使用FileChannel对文件进行复制,其实质还是通过
* FileInputStream和FileOutStream对文件流进行操作
* @param srcFile
* @param targetFile
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/24 14:43
*/
public static void copyFileByChannel(File srcFile, File targetFile) {
FileChannel inputFileChannel = null;
FileChannel outputFileChannel = null;
try {
inputFileChannel = new FileInputStream(srcFile).getChannel();
outputFileChannel = new FileOutputStream(targetFile).getChannel();
outputFileChannel.transferFrom(inputFileChannel, 0, inputFileChannel.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (outputFileChannel != null) {
IOUtils.closeQuietly(outputFileChannel);
}
if (inputFileChannel != null) {
IOUtils.closeQuietly(inputFileChannel);
}
}
}
3、通过commons-io工具包提供的copy方法拷贝
使用方法如下:
- 引入jar包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
- 调用方法
FileUtils.copyFile(srcFile, targetFile);
- copy方法的源码
/**
* Internal copy file method.
*
* @param srcFile the validated source file, must not be <code>null</code>
* @param destFile the validated destination file, must not be <code>null</code>
* @param preserveFileDate whether to preserve the file date
* @throws IOException if an error occurs
*/
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());
}
}
由以上源码可以看出FileUtils.copy(srcFile, targetFile)实际上使用的是FileChannel的方式进行文件拷贝。
二、文件压缩
文件压缩的方法有两种情况:
- 压缩的对象是文件夹
- 压缩的对象是文件
- 压缩对象是文件时,不需要考虑是否存在子项
/**
* @Description 压缩文件,将文件压缩在源文件所在的目录下
* @param srcFilePath 要压缩的文件
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/11 15:16
*/
public static void zipFile(String srcFilePath) {
File srcFile = new File(srcFilePath);
if (!srcFile.exists()){
return;
}
FileOutputStream fos = null;
ZipOutputStream zos = null;
//获取到文件路径
String zipFilePath = srcFile.getPath();
//压缩文件的路径
String destFilePath = zipFilePath.substring(0, zipFilePath.indexOf(".") + 1) + "zip";
File dstFile = new File(destFilePath);
try {
//输出的文件
fos = new FileOutputStream(dstFile);
CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
zos = new ZipOutputStream(cos);
//数据写入
writeDataToZip(srcFile, zos, "");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (zos != null) {
IOUtils.closeQuietly(zos);
}
if (fos != null) {
IOUtils.closeQuietly(fos);
}
}
}
/**
* @Description 数据写入压缩文件
* @param srcFile
* @param zos
* @param baseDir
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/28 17:18
*/
private static void writeDataToZip(File srcFile, ZipOutputStream zos, String baseDir) {
BufferedInputStream bis = null;
try {
//源文件流
bis = new BufferedInputStream(new FileInputStream(srcFile));
//创建压缩文件实体
String name = baseDir + srcFile.getName();
ZipEntry entry = new ZipEntry(name);
zos.putNextEntry(entry);
int count;
byte data[] = new byte[byteLen];
//写入数据
while ((count = bis.read(data, 0, byteLen)) != -1) {
zos.write(data, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
IOUtils.closeQuietly(bis);
}
}
}
2. 压缩对象是文件夹时,需要考虑文件夹层级和文件夹下的文件项
/**
* @Description 压缩一个文件夹下的所有文件
* @param srcFilePath
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/24 15:59
*/
public static void zipFilePath(String srcFilePath) {
System.out.println(srcFilePath);
File srcFile = new File(srcFilePath);
if (!srcFile.exists()) {
System.out.println("文件路径错误!");
return;
}
FileOutputStream fos = null;
ZipOutputStream zos = null;
//获取到文件路径
String zipFilePath = srcFile.getPath();
//压缩文件的路径
String destFilePath = srcFile.getParent() +"\"+ zipFilePath.substring(zipFilePath.lastIndexOf("\") + 1) + ".zip";
File dstFile = new File(destFilePath);
try {
fos = new FileOutputStream(dstFile);
CheckedOutputStream cos = new CheckedOutputStream(fos,new CRC32());
zos = new ZipOutputStream(cos);
File[] files = srcFile.listFiles();
//遍历文件压缩
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
zipDirectory(files[i], zos, files[i].getName() + "/");
} else {
writeDataToZip(files[i], zos, "");
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (zos != null) {
IOUtils.closeQuietly(zos);
}
if (fos != null) {
IOUtils.closeQuietly(fos);
}
}
}
/**
* @Description 遍历文件夹下的文件
* @param directoryFile
* @param zos
* @param baseDir
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/28 18:05
*/
private static void zipDirectory(File directoryFile, ZipOutputStream zos, String baseDir) {
File[] files = directoryFile.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
zipDirectory(files[i], zos, baseDir + files[i].getName() + "/");
} else {
if (files[i].exists()) {
writeDataToZip(files[i], zos, baseDir);
}
}
}
}
三、文件解压
将需要解压的.zip文件解压到目标文件夹下。
/**
* @Description 解压文件
* @param zipFile 需要解压的文件
* @param unZipPath 文件解压后存放的路径
* @Return void
* @Author Mr.Walloce
* @Date 2019/8/25 15:17
*/
public static void unZipFile(File zipFile, String unZipPath) {
File pathFile = new File(unZipPath);
if(!pathFile.exists()){
pathFile.mkdirs();
}
ZipFile zip = null;
InputStream is = null;
OutputStream os = null;
try {
zip = new ZipFile(zipFile);
//遍历解压文件
for(Enumeration entries = zip.entries();entries.hasMoreElements();){
ZipEntry entry = (ZipEntry)entries.nextElement();
String zipEntryName = entry.getName();
is = zip.getInputStream(entry);
String outPath = (unZipPath+"/"+zipEntryName).replaceAll("\*", "/");;
//判断路径是否存在,不存在则创建文件路径
File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
if(!file.exists()){
file.mkdirs();
}
//判断文件全路径是否为文件夹
if(new File(outPath).isDirectory()){
continue;
}
//解压后输出文件
os = new FileOutputStream(outPath);
byte[] buf1 = new byte[byteLen];
int len;
while((len = is.read(buf1)) > 0){
os.write(buf1,0,len);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
IOUtils.closeQuietly(is);
}
if (os != null) {
IOUtils.closeQuietly(os);
}
}
}
**
以上是我整理的一些对文件操作工具,仅供学习参考,如有错误希望能指出,大家共同学习进步!
**