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

Java中常用的9種文件下載方法總結(jié)

 更新時(shí)間:2023年09月17日 16:36:01   作者:趙俠客  
下載文件在我們項(xiàng)目很常見(jiàn),有下載視頻、文件、圖片、附件、導(dǎo)出Excel等,所以本文為大家整理了9中Java中常用的文件下載方式,希望對(duì)大家有所幫助

一、前言

下載文件在我們項(xiàng)目很常見(jiàn),有下載視頻、文件、圖片、附件、導(dǎo)出Excel、導(dǎo)出Zip壓縮文件等等,這里我對(duì)常見(jiàn)的下載做個(gè)簡(jiǎn)單的總結(jié),主要有文件下載、限速下載、多文件打包下載、URL文件打包下載、Excel導(dǎo)出下載、Excel批量導(dǎo)出Zip包下載、多線程加速下載。

二、搭建Spring Boot項(xiàng)目

搭建個(gè)SpringBoot Web項(xiàng)目,引用常用依賴,commons-io作常用IO操作,hutool-all、poi-ooxml做導(dǎo)出Excel操作,commons-compress做多線程壓縮。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.21</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>1.20</version>
        </dependency>

三、文件下載

3.1 單文件下載

最簡(jiǎn)單的下載就是提供一個(gè)文件下載接口,瀏覽器請(qǐng)求接口后預(yù)覽或者下載文件,這里以下載一個(gè)1.2G的視頻為例,直接看 /download接口

@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
        File file = new File("/Users/zxk/Movies/1.2G.mp4");
        response.setContentType("video/mp4;charset=utf8");
//設(shè)置下載文件名
        response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
//中文亂碼處理
//response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8") );
//網(wǎng)頁(yè)直接播放
//response.setHeader("Content-Disposition", "inline");
//下載進(jìn)度
        response.setContentLengthLong(file.length());
try (InputStream inputStream = new FileInputStream(file);
             OutputStream outputStream = response.getOutputStream()
        ) {
            IOUtils.copy(inputStream, outputStream);
        }
    }

這里有以下幾點(diǎn)需要注意:

  • 1. response.setContentType設(shè)置文件的類型
  • 2. Content-Disposition設(shè)置文件下載時(shí)顯示的文件名,如果有中文亂碼,需要URLEncode,如果希望瀏覽器直接打開(kāi)可以設(shè)置"inline"
  • 3. response.setContentLengthLong(file.length()),設(shè)置Http body長(zhǎng)度可以在下載時(shí)顯示進(jìn)度
  • 4. 下載完成需要關(guān)閉流,這里使用try-with-resource自動(dòng)關(guān)閉流

3.2限速下載

使用第一種下載速度會(huì)非常快,可能瞬間就將你的服務(wù)器帶寬占滿了,所以就需要限制下載速度。某盤(pán)開(kāi)會(huì)員和不開(kāi)會(huì)員下載速度相差非常大,就是針對(duì)不用同步給限制了不同的下載速度

@GetMapping("/limitSpeed")
    public void limitSpeed(@RequestParam(value = "speed", defaultValue = "1024") int speed, HttpServletResponse response) throws IOException {
        File path = new File("/Users/zxk/Movies/1.2G.mp4");
        response.setContentType("video/mp4;charset=utf8");
        response.setHeader("Content-Disposition", "attachment;filename=" + path.getName());
        response.setContentLengthLong(path.length());
        try (
                InputStream inputStream = new FileInputStream(path);
                OutputStream outputStream = response.getOutputStream()
        ) {
            byte[] buffer = new byte[1024];
            int length;
            SpeedLimiter speedLimiter = new SpeedLimiter(speed);
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                speedLimiter.delayNextBytes(length);
            }
        }
    }
public class SpeedLimiter {
    /** 速度上限(KB/s), 0=不限速 */
    private int maxRate = 1024;
    private long getMaxRateBytes(){
        return this.maxRate * 1024L;
    }
    private long getLessCountBytes() {
        long lcb = getMaxRateBytes() / 10;
        if (lcb < 10240) lcb = 10240;
        return lcb;
    }
    public SpeedLimiter(int maxRate) {
        this.setMaxRate(maxRate);
    }
    public synchronized void setMaxRate(int maxRate){
        this.maxRate = Math.max(maxRate, 0);
    }
    private long totalBytes = 0;
    private long tmpCountBytes = 0;
    private final long lastTime = System.currentTimeMillis();
    public synchronized void delayNextBytes(int len) {
        if (maxRate <= 0) return;
        totalBytes += len;
        tmpCountBytes += len;
        //未達(dá)到指定字節(jié)數(shù)跳過(guò)...
        if (tmpCountBytes < getLessCountBytes()) {
            return;
        }
        long nowTime = System.currentTimeMillis();
        long sendTime = nowTime - lastTime;
        long workTime = (totalBytes * 1000) / getMaxRateBytes();
        long delayTime = workTime - sendTime;
        if (delayTime > 0) {
            try {
                Thread.sleep(delayTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tmpCountBytes = 0;
        }
    }
}

3.3多文件打成ZIP包下載

有了單文件下載,肯定就用多文件下載,一般瀏覽器下載多個(gè)文件是將多個(gè)文件打包成一個(gè)Zip文件下載。

@GetMapping("/zip")
    public void zip(HttpServletResponse response) throws IOException {
        File file1 = new File("/Users/zxk/Movies/2.mp4");
        File file2 = new File("/Users/zxk/Movies/2.mp4");
        List<File> files = Arrays.asList(file2, file1);
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=demo.zip");
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
            zipOutputStream.setLevel(0);
            files.forEach(f -> {
                try (FileInputStream inputStream = new FileInputStream(f)) {
                    zipOutputStream.putNextEntry(new ZipEntry(f.getName()));
                    IOUtils.copy(inputStream, zipOutputStream);
                    zipOutputStream.closeEntry();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            zipOutputStream.flush();
            zipOutputStream.finish();
        }
    }

多文件打成Zip包注意事項(xiàng):

  • 1. zipOutputStream.setLevel(0)設(shè)置壓縮等級(jí),0為不壓縮,這樣可以提升下載速度
  • 2. 多個(gè)文件打包下載時(shí)并不是所有文件壓縮完成后才開(kāi)始下載,而是邊壓縮邊下載,這樣用戶點(diǎn)了下載后,下載任務(wù)會(huì)直接進(jìn)入瀏覽器下載列表

3.4整個(gè)文件夾下載

有時(shí)需要遞歸將整個(gè)文件夾打包下載下來(lái)

@GetMapping("/dir")
    public void dir(HttpServletResponse response) throws IOException {
        File dir = new File("/Users/zxk/Movies/download");
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=demo.zip");
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
            zipOutputStream.setLevel(0);
            zip(zipOutputStream, "", dir);
            zipOutputStream.flush();
            zipOutputStream.finish();
        }
    }
    public void zip(ZipOutputStream zipOutputStream, String parentPath, File file) throws IOException {
        if (file.isDirectory()) {
            File[] subFiles = file.listFiles();
            if (subFiles != null) {
                for (File f : subFiles) {
                    zip(zipOutputStream, parentPath + file.getName() + "/", f);
                }
            }
        } else {
            try (FileInputStream fileInputStream = new FileInputStream(file)) {
                zipOutputStream.putNextEntry(new ZipEntry(parentPath + file.getName()));
                IOUtils.copy(fileInputStream, zipOutputStream);
            }
        }
    }

注意事項(xiàng):

1. 會(huì)遞歸整個(gè)文件夾,文件夾文件不能太多

3.5通過(guò)URL打包下載

有時(shí)我們的文件可能是存在云存儲(chǔ)上,數(shù)據(jù)庫(kù)里存的是文件的ULR,下載時(shí)我們就需要通過(guò)URL將多個(gè)文件打包下載

@GetMapping("/urlZip")
    public void urlZip(HttpServletResponse response) throws IOException {
        List<String> urls = Arrays.asList("https://demo.com/11666832527556.jpeg",
                "https://demo.com/11666831385156.jpeg",
                "https://demo.com/11666829917700.jpeg",
                "https://demo.com/11666762702021.png",
                "https://demo.com/11666762702020.webp",
                "https://demo.com/11666549651972.jpg",
                "https://demo.com/11666524497476.jpeg",
                "https://demo.com/11666507113092.jpg");
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=demo.zip");
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
            zipOutputStream.setLevel(0);
            urls.forEach(f -> {
                try {
                    zipOutputStream.putNextEntry(new ZipEntry(StringUtils.getFilename(f)));
                    HttpUtil.download(f, zipOutputStream, false);
                    zipOutputStream.closeEntry();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            zipOutputStream.flush();
            zipOutputStream.finish();
        }
    }

3.6導(dǎo)出Excel下載

有些下載的文件并不存在,而是先從數(shù)據(jù)庫(kù)中查出數(shù)據(jù),再動(dòng)態(tài)生成文件,再提供給用戶下載,這里我們以導(dǎo)出單個(gè)Excel文件為例:

 @GetMapping("/excel")
    public void excel(HttpServletResponse response) throws IOException {
        List<List<Integer>> rows = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            rows.add(IntStream.range(i, i + 100).boxed().collect(Collectors.toList()));
        }
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=test.xls");
        try (OutputStream out = response.getOutputStream();
             ExcelWriter writer = ExcelUtil.getWriter()) {
            writer.write(rows);
            writer.flush(out, true);
        }
    }

3.7批量導(dǎo)出Excel打包下載

很多業(yè)務(wù)需要一次性導(dǎo)出多個(gè)Excel,這里我們可以將多個(gè)Excel壓縮成一個(gè)Zip文件下載下來(lái),這里以動(dòng)態(tài)生成10個(gè)Excel主例:

    @GetMapping("/excelZip")
    public void excelZip(HttpServletResponse response) throws IOException {
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=demo.zip");
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
            zipOutputStream.setLevel(0);
            for (int i = 0; i < 10; i++) {
                zipOutputStream.putNextEntry(new ZipEntry(String.format("%s.xls", i)));
                try (ExcelWriter writer = ExcelUtil.getWriter()) {
                    writer.write(generateData());
                    writer.flush(zipOutputStream);
                }
            }
            zipOutputStream.flush();
            zipOutputStream.finish();
        }
    }
   private List<List<Integer>> generateData() {
        List<List<Integer>> rows = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            rows.add(IntStream.range(i, i + 100).boxed().collect(Collectors.toList()));
        }
        return rows;
    }

3.8多線程加速下載

有時(shí)下載數(shù)據(jù)量比較多,單線程打包會(huì)比較慢,這里我們就需要使用多線程并發(fā)打包提高打包速度,這里我以多線程下載多個(gè)URL文件為例使用commons-compress的ParallelScatterZipCreator多線程并發(fā)打包

 public static final ThreadFactory factory = new ThreadFactoryBuilder().setNamePrefix("compressFileList-pool-").build();
  public static final ExecutorService executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20), factory);
    @GetMapping("/parallelZip")
    public void excelZipThread(HttpServletResponse response) throws IOException {
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=demo.zip");
        List<String> urls = Arrays.asList("https://demo.com/11671291835144.png",
        "https://demo.com/11671291834824.png",
        "https://demo.com/11671291833928.png",
        "https://demo.com/11671291833800.png",
        "https://demo.com/11671291833480.png",
        "https://demo.com/11671291828232.png",
        "https://demo.com/11671291827528.png",
        "https://demo.com/11671291825737.png",
        "https://demo.com/11671291825736.png");
        ParallelScatterZipCreator parallelScatterZipCreator = new ParallelScatterZipCreator(executor);
        try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(response.getOutputStream())) {
            zipArchiveOutputStream.setLevel(0);
            urls.forEach(x -> {
                ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(StringUtils.getFilename(x));
                zipArchiveEntry.setMethod(ZipArchiveEntry.STORED);
                InputStreamSupplier inputStreamSupplier = () -> URLUtil.getStream(URLUtil.url(x));
                parallelScatterZipCreator.addArchiveEntry(zipArchiveEntry, inputStreamSupplier);
            });
            parallelScatterZipCreator.writeTo(zipArchiveOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3.9多線程批量導(dǎo)Excel打包下載

這種是比較復(fù)雜的,動(dòng)態(tài)生成多個(gè)Excel文件后,使用多線程打成ZIP包下載

@GetMapping("/parallelexcelZip")
    public void parallelexcelZip(HttpServletResponse response) throws IOException {
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=demo.zip");
        ParallelScatterZipCreator parallelScatterZipCreator = new ParallelScatterZipCreator(executor);
        try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(response.getOutputStream())) {
            zipArchiveOutputStream.setLevel(0);
            IntStream.range(1,10).forEach(x -> {
                InputStreamSupplier inputStreamSupplier = () ->{
                    ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
                    try(ExcelWriter writer=ExcelUtil.getWriter()) {
                        writer.write(generateData());
                        writer.flush(outputStream);
                    }
                    return  new ByteArrayInputStream(outputStream.toByteArray());
                };
                ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(String.format("%s.xls",x));
                zipArchiveEntry.setMethod(ZipArchiveEntry.STORED);
                parallelScatterZipCreator.addArchiveEntry(zipArchiveEntry, inputStreamSupplier);
            });
            parallelScatterZipCreator.writeTo(zipArchiveOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

四、總結(jié)

本文主要總結(jié)了常用9種常見(jiàn)的文件下載操作,并提供對(duì)應(yīng)的演示代碼,當(dāng)然還有一些沒(méi)有總結(jié)到的,如分片下載、斷點(diǎn)結(jié)續(xù)下、分布式下載限速等,這些高級(jí)下載在普通項(xiàng)目中用到的不太多所以沒(méi)有總結(jié)。

到此這篇關(guān)于Java中常用的9種文件下載方法總結(jié)的文章就介紹到這了,更多相關(guān)Java文件下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Java字節(jié)碼編程之非常好用的javassist

    詳解Java字節(jié)碼編程之非常好用的javassist

    這篇文章主要介紹了詳解Java字節(jié)碼編程之非常好用的javassist,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 解決ResourceBundle.getBundle文件路徑問(wèn)題

    解決ResourceBundle.getBundle文件路徑問(wèn)題

    這篇文章主要介紹了解決ResourceBundle.getBundle文件路徑問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java打印九九乘法表代碼詳情

    Java打印九九乘法表代碼詳情

    這篇文章主要介紹了Java打印九九乘法表,使用了雙重for循環(huán),使用do{}while()實(shí)現(xiàn)打印九九乘法表這些好玩的語(yǔ)法實(shí)現(xiàn),感興趣的小伙伴可參考下面文章內(nèi)容
    2021-09-09
  • springcloud?gateway實(shí)現(xiàn)簡(jiǎn)易版灰度路由步驟詳解

    springcloud?gateway實(shí)現(xiàn)簡(jiǎn)易版灰度路由步驟詳解

    這篇文章主要為大家介紹了springcloud?gateway實(shí)現(xiàn)簡(jiǎn)易版灰度路由步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 使用spring@value加載時(shí)機(jī)

    使用spring@value加載時(shí)機(jī)

    這篇文章主要介紹了使用spring@value加載時(shí)機(jī)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring Aop之AspectJ注解配置實(shí)現(xiàn)日志管理的方法

    Spring Aop之AspectJ注解配置實(shí)現(xiàn)日志管理的方法

    下面小編就為大家分享一篇Spring Aop之AspectJ注解配置實(shí)現(xiàn)日志管理的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • 深入理解Maven環(huán)境搭建和介紹

    深入理解Maven環(huán)境搭建和介紹

    這篇文章主要介紹了深入理解Maven環(huán)境搭建和介紹,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • 使用Spring動(dòng)態(tài)修改bean屬性的key

    使用Spring動(dòng)態(tài)修改bean屬性的key

    這篇文章主要介紹了使用Spring動(dòng)態(tài)修改bean屬性的key方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java面試題之基本語(yǔ)法(圖解)

    Java面試題之基本語(yǔ)法(圖解)

    這篇文章主要介紹了關(guān)于Java面試題之基本語(yǔ)法的相關(guān)資料,文中通過(guò)圖片說(shuō)明介紹的很詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來(lái)一起看看吧。
    2017-02-02
  • mybatis?實(shí)體類字段大小寫(xiě)問(wèn)題?字段獲取不到值的解決

    mybatis?實(shí)體類字段大小寫(xiě)問(wèn)題?字段獲取不到值的解決

    這篇文章主要介紹了mybatis?實(shí)體類字段大小寫(xiě)問(wèn)題?字段獲取不到值的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評(píng)論