欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一 前言

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

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

二 壓縮文件

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

壓縮文件操作,會(huì)使用到一個(gè)類(lèi),即ZipOutputStream。

2.1 壓縮多個(gè)文件

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

  /**
   * 壓縮多個(gè)文件,壓縮后的所有文件在同一目錄下
   * 
   * @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));
      // 遍歷每一個(gè)文件,進(jìn)行輸出
      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();
        }
      }
    }
  }

測(cè)試,將D盤(pán)下的infp.txt和infp1.txt文件壓縮到D盤(pán)下,壓縮文件名為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 壓縮文件或文件樹(shù)

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

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 { // 單個(gè)文件
        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 當(dāng)前文件
   * @param zipOutputStream 壓縮輸出流
   * @param relativePath 相對(duì)路徑
   * @throws IOException IO異常
   */
  private static void zip(File file, ZipOutputStream zipOutputStream, String relativePath)
      throws IOException {

    FileInputStream fileInputStream = null;
    try {
      if (file.isDirectory()) { // 當(dāng)前為文件夾
        // 當(dāng)前文件夾下的所有文件
        File[] list = file.listFiles();
        if (null != list) {
          // 計(jì)算當(dāng)前的相對(duì)路徑
          relativePath += (relativePath.length() == 0 ? "" : "/") + file.getName();
          // 遞歸壓縮每個(gè)文件
          for (File f : list) {
            zip(f, zipOutputStream, relativePath);
          }
        }
      } else { // 壓縮文件
        // 計(jì)算文件的相對(duì)路徑
        relativePath += (relativePath.length() == 0 ? "" : "/") + file.getName();
        // 寫(xiě)入單個(gè)文件
        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 借助文件訪問(wèn)器壓縮

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

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

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);

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

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

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

  // 遍歷完一個(gè)目錄下的所有文件后,再調(diào)用這個(gè)目錄的方法
  @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類(lèi),可以讀取到壓縮包中的每一個(gè)文件,然后根據(jù)讀取到的文件屬性,寫(xiě)入到相應(yīng)路徑下即可。對(duì)于解壓壓縮包中是文件樹(shù)的結(jié)構(gòu),每讀取到一個(gè)文件后,如果是多層路徑下的文件,需要先創(chuàng)建父目錄,再寫(xiě)入文件流。

package com.nobody.zip;

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

/**
 * @Description 解壓縮文件工具類(lèi)
 * @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)建解壓目標(biāo)文件夾失敗");
      }
    }
    // 讀入流
    ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
    // 遍歷每一個(gè)文件
    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());
        // 寫(xiě)出文件流
        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ò)程中,主要是對(duì)流的讀取操作,注意進(jìn)行異常處理,以及關(guān)閉流。
web應(yīng)用中,通過(guò)接口可以實(shí)現(xiàn)文件上傳下載,對(duì)應(yīng)的我們只要把壓縮后的文件,寫(xiě)入到response.getOutputStream()輸出流即可。
解壓縮文件時(shí),注意空文件夾的處理。

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

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

相關(guān)文章

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

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

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

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

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

    Spring注解實(shí)現(xiàn)Bean自動(dòng)裝配示例詳解

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

    java中判斷String類(lèi)型為空和null的幾種方法

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

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

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

    Java之通過(guò)OutputStream寫(xiě)入文件與文件復(fù)制問(wèn)題

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

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

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

    MyBatis中動(dòng)態(tài)SQL語(yǔ)句@Provider的用法

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

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

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

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

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

最新評(píng)論