亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java 如何實現(xiàn)解壓縮文件和文件夾

 更新時間:2021年03月11日 08:31:15   作者:Mr_ηobody  
這篇文章主要介紹了Java 如何實現(xiàn)解壓縮文件和文件夾,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下

一 前言

項目開發(fā)中,總會遇到解壓縮文件的時候。比如,用戶下載多個文件時,服務(wù)端可以將多個文件壓縮成一個文件(例如xx.zip或xx.rar)。用戶上傳資料時,允許上傳壓縮文件,服務(wù)端進行解壓讀取每一個文件。

基于通用性,以下介紹幾種解壓縮文件的方式,包裝成工具類,供平時開發(fā)使用。

二 壓縮文件

壓縮文件,顧名思義,即把一個或多個文件壓縮成一個文件。壓縮也有2種形式,一種是將所有文件壓縮到同一目錄下,此種方式要注意文件重名覆蓋的問題。另一種是按原有文件樹結(jié)構(gòu)進行壓縮,即壓縮后的文件樹結(jié)構(gòu)保持不變。

壓縮文件操作,會使用到一個類,即ZipOutputStream。

2.1 壓縮多個文件

此方法將所有文件壓縮到同一個目錄下。方法傳入多個文件列表,和一個最終壓縮到的文件路徑名。

  /**
   * 壓縮多個文件,壓縮后的所有文件在同一目錄下
   * 
   * @param zipFileName 壓縮后的文件名
   * @param files 需要壓縮的文件列表
   * @throws IOException IO異常
   */
  public static void zipMultipleFiles(String zipFileName, File... files) throws IOException {
    ZipOutputStream zipOutputStream = null;
    try {
      // 輸出流
      zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
      // 遍歷每一個文件,進行輸出
      for (File file : files) {
        zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
        FileInputStream fileInputStream = new FileInputStream(file);
        int readLen;
        byte[] buffer = new byte[1024];
        while ((readLen = fileInputStream.read(buffer)) != -1) {
          zipOutputStream.write(buffer, 0, readLen);
        }
        // 關(guān)閉流
        fileInputStream.close();
        zipOutputStream.closeEntry();
      }
    } finally {
      if (null != zipOutputStream) {
        try {
          zipOutputStream.close();
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }
  }

測試,將D盤下的infp.txt和infp1.txt文件壓縮到D盤下,壓縮文件名為my.zip。

  public static void main(String[] args) throws Exception {
    zipMultipleFiles("D:/my.zip", new File("D:/infp.txt"), new File("D:/infp1.txt"));
  }

2.2 壓縮文件或文件樹

此方法將文件夾下的所有文件按原有的樹形結(jié)構(gòu)壓縮到文件中,也支持壓縮單個文件。原理也簡單,無非就是遞歸遍歷文件樹中的每一個文件,進行壓縮。有個注意的點每一個文件的寫入路徑是基于壓縮文件位置的相對路徑。

package com.nobody.zip;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtils {

  /**
   * 壓縮文件或文件夾(包括所有子目錄文件)
   *
   * @param sourceFile 源文件
   * @param format 格式(zip或rar)
   * @throws IOException 異常信息
   */
  public static void zipFileTree(File sourceFile, String format) throws IOException {
    ZipOutputStream zipOutputStream = null;
    try {
      String zipFileName;
      if (sourceFile.isDirectory()) { // 目錄
        zipFileName = sourceFile.getParent() + File.separator + sourceFile.getName() + "."
            + format;
      } else { // 單個文件
        zipFileName = sourceFile.getParent()
            + sourceFile.getName().substring(0, sourceFile.getName().lastIndexOf("."))
            + "." + format;
      }
      // 壓縮輸出流
      zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
      zip(sourceFile, zipOutputStream, "");
    } finally {
      if (null != zipOutputStream) {
        // 關(guān)閉流
        try {
          zipOutputStream.close();
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }
  }

  /**
   * 遞歸壓縮文件
   * 
   * @param file 當前文件
   * @param zipOutputStream 壓縮輸出流
   * @param relativePath 相對路徑
   * @throws IOException IO異常
   */
  private static void zip(File file, ZipOutputStream zipOutputStream, String relativePath)
      throws IOException {

    FileInputStream fileInputStream = null;
    try {
      if (file.isDirectory()) { // 當前為文件夾
        // 當前文件夾下的所有文件
        File[] list = file.listFiles();
        if (null != list) {
          // 計算當前的相對路徑
          relativePath += (relativePath.length() == 0 ? "" : "/") + file.getName();
          // 遞歸壓縮每個文件
          for (File f : list) {
            zip(f, zipOutputStream, relativePath);
          }
        }
      } else { // 壓縮文件
        // 計算文件的相對路徑
        relativePath += (relativePath.length() == 0 ? "" : "/") + file.getName();
        // 寫入單個文件
        zipOutputStream.putNextEntry(new ZipEntry(relativePath));
        fileInputStream = new FileInputStream(file);
        int readLen;
        byte[] buffer = new byte[1024];
        while ((readLen = fileInputStream.read(buffer)) != -1) {
          zipOutputStream.write(buffer, 0, readLen);
        }
        zipOutputStream.closeEntry();
      }
    } finally {
      // 關(guān)閉流
      if (fileInputStream != null) {
        try {
          fileInputStream.close();
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }
  }

  public static void main(String[] args) throws Exception {
    String path = "D:/test";
    String format = "zip";
    zipFileTree(new File(path), format);
  }
}

上例將test目錄下的所有文件壓縮到同一目錄下的test.zip文件中。

2.3 借助文件訪問器壓縮

還有一種更簡單的方式,我們不自己寫遞歸遍歷。借助Java原生類,SimpleFileVisitor,它提供了幾個訪問文件的方法,其中有個方法visitFile,對于文件樹中的每一個文件(文件夾除外),都會調(diào)用這個方法。我們只要寫一個類繼承SimpleFileVisitor,然后重寫visitFile方法,實現(xiàn)將每一個文件寫入到壓縮文件中即可。

當然,除了visitFile方法,它里面還有preVisitDirectory,postVisitDirectory,visitFileFailed等方法,通過方法名大家也猜出什么意思了。

package com.nobody.zip;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Description
 * @Author Mr.nobody
 * @Date 2021/3/8
 * @Version 1.0.0
 */
public class ZipFileTree extends SimpleFileVisitor<Path> {

  // zip輸出流
  private ZipOutputStream zipOutputStream;
  // 源目錄
  private Path sourcePath;

  public ZipFileTree() {}

  /**
   * 壓縮目錄以及所有子目錄文件
   *
   * @param sourceDir 源目錄
   */
  public void zipFile(String sourceDir) throws IOException {
    try {
      // 壓縮后的文件和源目錄在同一目錄下
      String zipFileName = sourceDir + ".zip";
      this.zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
      this.sourcePath = Paths.get(sourceDir);

      // 開始遍歷文件樹
      Files.walkFileTree(sourcePath, this);
    } finally {
      // 關(guān)閉流
      if (null != zipOutputStream) {
        zipOutputStream.close();
      }
    }
  }

  // 遍歷到的每一個文件都會執(zhí)行此方法
  @Override
  public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
    // 取相對路徑
    Path targetFile = sourcePath.relativize(file);
    // 寫入單個文件
    zipOutputStream.putNextEntry(new ZipEntry(targetFile.toString()));
    byte[] bytes = Files.readAllBytes(file);
    zipOutputStream.write(bytes, 0, bytes.length);
    zipOutputStream.closeEntry();
    // 繼續(xù)遍歷
    return FileVisitResult.CONTINUE;
  }

  // 遍歷每一個目錄時都會調(diào)用的方法
  @Override
  public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
      throws IOException {
    return super.preVisitDirectory(dir, attrs);
  }

  // 遍歷完一個目錄下的所有文件后,再調(diào)用這個目錄的方法
  @Override
  public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
    return super.postVisitDirectory(dir, exc);
  }

  // 遍歷文件失敗后調(diào)用的方法
  @Override
  public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
    return super.visitFileFailed(file, exc);
  }

  public static void main(String[] args) throws IOException {
    // 需要壓縮源目錄
    String sourceDir = "D:/test";
    // 壓縮
    new ZipFileTree().zipFile(sourceDir);
  }
}

三 解壓文件

解壓壓縮包,借助ZipInputStream類,可以讀取到壓縮包中的每一個文件,然后根據(jù)讀取到的文件屬性,寫入到相應(yīng)路徑下即可。對于解壓壓縮包中是文件樹的結(jié)構(gòu),每讀取到一個文件后,如果是多層路徑下的文件,需要先創(chuàng)建父目錄,再寫入文件流。

package com.nobody.zip;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * @Description 解壓縮文件工具類
 * @Author Mr.nobody
 * @Date 2021/3/8
 * @Version 1.0.0
 */
public class ZipUtils {

  /**
   * 解壓
   * 
   * @param zipFilePath 帶解壓文件
   * @param desDirectory 解壓到的目錄
   * @throws Exception
   */
  public static void unzip(String zipFilePath, String desDirectory) throws Exception {

    File desDir = new File(desDirectory);
    if (!desDir.exists()) {
      boolean mkdirSuccess = desDir.mkdir();
      if (!mkdirSuccess) {
        throw new Exception("創(chuàng)建解壓目標文件夾失敗");
      }
    }
    // 讀入流
    ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
    // 遍歷每一個文件
    ZipEntry zipEntry = zipInputStream.getNextEntry();
    while (zipEntry != null) {
      if (zipEntry.isDirectory()) { // 文件夾
        String unzipFilePath = desDirectory + File.separator + zipEntry.getName();
        // 直接創(chuàng)建
        mkdir(new File(unzipFilePath));
      } else { // 文件
        String unzipFilePath = desDirectory + File.separator + zipEntry.getName();
        File file = new File(unzipFilePath);
        // 創(chuàng)建父目錄
        mkdir(file.getParentFile());
        // 寫出文件流
        BufferedOutputStream bufferedOutputStream =
            new BufferedOutputStream(new FileOutputStream(unzipFilePath));
        byte[] bytes = new byte[1024];
        int readLen;
        while ((readLen = zipInputStream.read(bytes)) != -1) {
          bufferedOutputStream.write(bytes, 0, readLen);
        }
        bufferedOutputStream.close();
      }
      zipInputStream.closeEntry();
      zipEntry = zipInputStream.getNextEntry();
    }
    zipInputStream.close();
  }

  // 如果父目錄不存在則創(chuàng)建
  private static void mkdir(File file) {
    if (null == file || file.exists()) {
      return;
    }
    mkdir(file.getParentFile());
    file.mkdir();
  }

  public static void main(String[] args) throws Exception {
    String zipFilePath = "D:/test.zip";
    String desDirectory = "D:/a";
    unzip(zipFilePath, desDirectory);
  }
}

四 總結(jié)

在解壓縮文件過程中,主要是對流的讀取操作,注意進行異常處理,以及關(guān)閉流。
web應(yīng)用中,通過接口可以實現(xiàn)文件上傳下載,對應(yīng)的我們只要把壓縮后的文件,寫入到response.getOutputStream()輸出流即可。
解壓縮文件時,注意空文件夾的處理。

此演示項目已上傳到Github,如有需要可自行下載,歡迎 Star 。 https://github.com/LucioChn/common-utils

以上就是Java 如何實現(xiàn)解壓縮文件和文件夾的詳細內(nèi)容,更多關(guān)于Java 解壓縮文件和文件夾的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文詳解Java閉鎖和柵欄的實現(xiàn)

    一文詳解Java閉鎖和柵欄的實現(xiàn)

    閉鎖與柵欄是在多線程編程中的概念,因為在多線程中,我們不能控制線程的執(zhí)行狀態(tài),所以給線程加鎖,讓其按照我們的想法有秩序的執(zhí)行。本文將詳解Java閉鎖和柵欄的實現(xiàn),需要的可以參考一下
    2022-06-06
  • 聊聊java中引用數(shù)據(jù)類型有哪些

    聊聊java中引用數(shù)據(jù)類型有哪些

    這篇文章主要介紹了java中引用數(shù)據(jù)類型有哪些,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Spring注解實現(xiàn)Bean自動裝配示例詳解

    Spring注解實現(xiàn)Bean自動裝配示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring注解實現(xiàn)Bean自動裝配的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • java中判斷String類型為空和null的幾種方法

    java中判斷String類型為空和null的幾種方法

    判斷一個字符串是否為空或者為null是一個常見的操作,本文主要介紹了java中判斷String類型為空和null的幾種方法,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • SpringBoot整合WebService服務(wù)的實現(xiàn)代碼

    SpringBoot整合WebService服務(wù)的實現(xiàn)代碼

    WebService是一個SOA(面向服務(wù)的編程)的架構(gòu),它是不依賴于語言,不依賴于平臺,可以實現(xiàn)不同的語言間的相互調(diào)用,通過Internet進行基于Http協(xié)議的網(wǎng)絡(luò)應(yīng)用間的交互,這篇文章主要介紹了SpringBoot整合WebService服務(wù)的實例代碼,需要的朋友可以參考下
    2022-02-02
  • Java之通過OutputStream寫入文件與文件復(fù)制問題

    Java之通過OutputStream寫入文件與文件復(fù)制問題

    這篇文章主要介紹了Java之通過OutputStream寫入文件與文件復(fù)制問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java基礎(chǔ)教程之List集合的常用方法

    Java基礎(chǔ)教程之List集合的常用方法

    這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之List集合的常用方法,在Java編程中List集合是一種常用的數(shù)據(jù)結(jié)構(gòu),用于存儲一組元素,有時候我們需要對List集合中的元素進行分組操作,即將相同屬性或特征的元素歸類到一組,需要的朋友可以參考下
    2023-10-10
  • MyBatis中動態(tài)SQL語句@Provider的用法

    MyBatis中動態(tài)SQL語句@Provider的用法

    本文主要介紹了MyBatis中動態(tài)SQL語句@Provider的用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • JAVA圖形界面(GUI)之表格的示例代碼

    JAVA圖形界面(GUI)之表格的示例代碼

    這篇文章主要介紹了JAVA圖形界面(GUI)之表格的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • Java使用Maven BOM統(tǒng)一管理版本號的實現(xiàn)

    Java使用Maven BOM統(tǒng)一管理版本號的實現(xiàn)

    這篇文章主要介紹了Java使用Maven BOM統(tǒng)一管理版本號的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04

最新評論