一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 關于SpringBoot大文件RestTemplate下載解決方案

關于SpringBoot大文件RestTemplate下載解決方案

2022-02-27 15:11人無名,則可專心練劍 Java教程

這篇文章主要介紹了SpringBoot大文件RestTemplate下載解決方案,最近結合網上案例及自己總結,寫了一個分片下載tuling/fileServer項目,需要的朋友可以參考下

近期基于項目上使用到的RestTemplate下載文件流,遇到1G以上的大文件,下載需要3-4分鐘,因為調用API接口沒有做分片與多線程, 文件流全部采用同步方式加載,性能很慢。最近結合網上案例及自己總結,寫了一個分片下載tuling/fileServer項目: 1.包含同步下載文件流在瀏覽器加載輸出相關代碼; 2.包含分片多線程下載分片文件及合并文件相關代碼;

另外在DownloadThread項目中使用代碼完成了一個遠程RestUrl請求去獲取一個遠端資源大文件進行多線程分片下載 到本地的一個案例,可以下載一些諸如.mp4/.avi等視頻類大文件。相關代碼也一并打包上傳。

同步下載,支持分片下載Range主要代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@Controller
public class DownLoadController {
    private static final String UTF8 = "UTF-8";
    @RequestMapping("/download")
    public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        File file = new File("D:\\DevTools\\ideaIU-2021.1.3.exe");
        response.setCharacterEncoding(UTF8);
        InputStream is = null;
        OutputStream os = null;
        try {
            // 分片下載 Range表示方式 bytes=100-1000  100-
            long fSize = file.length();
            response.setContentType("application/x-download");
            String fileName = URLEncoder.encode(file.getName(), UTF8);
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            // 支持分片下載
            response.setHeader("Accept-Range", "bytes");
            response.setHeader("fSize", String.valueOf(fSize));
            response.setHeader("fName", fileName);
 
            long pos = 0, last = fSize - 1, sum = 0;
            if (null != request.getHeader("Range")) {
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                String numberRange = request.getHeader("Range").replaceAll("bytes=", "");
                String[] strRange = numberRange.split("-");
                if (strRange.length == 2) {
                    pos = Long.parseLong(strRange[0].trim());
                    last = Long.parseLong(strRange[1].trim());
                    if (last > fSize-1) {
                        last = fSize - 1;
                    }
                } else {
                    pos = Long.parseLong(numberRange.replaceAll("-", "").trim());
                }
            }
            long rangeLength = last - pos + 1;
            String contentRange = new StringBuffer("bytes").append(pos).append("-").append(last).append("/").append(fSize).toString();
            response.setHeader("Content-Range", contentRange);
            response.setHeader("Content-Length", String.valueOf(rangeLength));
 
            os = new BufferedOutputStream(response.getOutputStream());
            is = new BufferedInputStream(new FileInputStream(file));
            is.skip(pos);
            byte[] buffer = new byte[1024];
            int length = 0;
            while (sum < rangeLength) {
                int readLength = (int) (rangeLength - sum);
                length = is.read(buffer, 0, (rangeLength - sum) <= buffer.length ? readLength : buffer.length);
                sum += length;
                os.write(buffer,0, length);
            }
            System.out.println("下載完成");
        }finally {
            if (is != null){
                is.close();
            }
            if (os != null){
                os.close();
            }
        }
    }
}

多線程分片下載分片文件,下載完成之后合并分片主要代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
@RestController
public class DownloadClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(DownloadClient.class);
    private final static long PER_PAGE = 1024L * 1024L * 50L;
    private final static String DOWN_PATH = "F:\\fileItem";
    ExecutorService taskExecutor = Executors.newFixedThreadPool(10);
 
    @RequestMapping("/downloadFile")
    public String downloadFile() {
        // 探測下載
        FileInfo fileInfo = download(0, 10, -1, null);
        if (fileInfo != null) {
            long pages =  fileInfo.fSize / PER_PAGE;
            for (long i = 0; i <= pages; i++) {
                Future<FileInfo> future = taskExecutor.submit(new DownloadThread(i * PER_PAGE, (i + 1) * PER_PAGE - 1, i, fileInfo.fName));
                if (!future.isCancelled()) {
                    try {
                        fileInfo = future.get();
                    } catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace();
                    }
                }
            }
            return System.getProperty("user.home") + "\\Downloads\\" + fileInfo.fName;
        }
        return null;
    }
 
    class FileInfo {
        long fSize;
        String fName;
 
        public FileInfo(long fSize, String fName) {
            this.fSize = fSize;
            this.fName = fName;
        }
    }
 
    /**
     * 根據開始位置/結束位置
     * 分片下載文件,臨時存儲文件分片
     * 文件大小=結束位置-開始位置
     *
     * @return
     */
    private FileInfo download(long start, long end, long page, String fName) {
        File dir = new File(DOWN_PATH);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 斷點下載
        File file = new File(DOWN_PATH, page + "-" + fName);
        if (file.exists() && page != -1 && file.length() == PER_PAGE) {
            return null;
        }
        try {
            HttpClient client = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/download");
            httpGet.setHeader("Range", "bytes=" + start + "-" + end);
            HttpResponse response = client.execute(httpGet);
            String fSize = response.getFirstHeader("fSize").getValue();
            fName = URLDecoder.decode(response.getFirstHeader("fName").getValue(), "UTF-8");
            HttpEntity entity = response.getEntity();
            InputStream is = entity.getContent();
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int ch;
            while ((ch = is.read(buffer)) != -1) {
                fos.write(buffer, 0, ch);
            }
            is.close();
            fos.flush();
            fos.close();
            // 最后一個分片
            if (end - Long.parseLong(fSize) > 0) {
                // 開始合并文件
                mergeFile(fName, page);
            }
 
            return new FileInfo(Long.parseLong(fSize), fName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
 
    private void mergeFile(String fName, long page) {
        File file = new File(DOWN_PATH, fName);
        try {
            BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
            for (long i = 0; i <= page; i++) {
                File tempFile = new File(DOWN_PATH, i + "-" + fName);
                while (!file.exists() || (i != page && tempFile.length() < PER_PAGE)) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                byte[] bytes = FileUtils.readFileToByteArray(tempFile);
                os.write(bytes);
                os.flush();
                tempFile.delete();
            }
            File testFile = new File(DOWN_PATH, -1 + "-null");
            testFile.delete();
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 獲取遠程文件尺寸
     */
    private long getRemoteFileSize(String remoteFileUrl) throws IOException {
        long fileSize = 0;
        HttpURLConnection httpConnection = (HttpURLConnection) new URL(remoteFileUrl).openConnection();
        //使用HEAD方法
        httpConnection.setRequestMethod("HEAD");
        int responseCode = httpConnection.getResponseCode();
        if (responseCode >= 400) {
            LOGGER.debug("Web服務器響應錯誤!");
            return 0;
        }
        String sHeader;
        for (int i = 1;; i++) {
            sHeader = httpConnection.getHeaderFieldKey(i);
            if (sHeader != null && sHeader.equals("Content-Length")) {
                LOGGER.debug("文件大小ContentLength:" + httpConnection.getContentLength());
                fileSize = Long.parseLong(httpConnection.getHeaderField(sHeader));
                break;
            }
        }
        return fileSize;
    }
 
    class DownloadThread implements Callable<FileInfo> {
        long start;
        long end;
        long page;
        String fName;
 
        public DownloadThread(long start, long end, long page, String fName) {
            this.start = start;
            this.end = end;
            this.page = page;
            this.fName = fName;
        }
 
        @Override
        public FileInfo call() {
            return download(start, end, page, fName);
        }
    }
}

代碼都在本地親測(已修復Bug)可用,目前比較欠缺的是沒有實現在分片下載時對應瀏覽器進行下載展示,需要暫存在本地磁盤目錄。 目前將代碼開源,希望能有更好解決方案的Coder Fork支持!也歡迎Star捧場。

博文參考了圖靈學院相關的分片下載案例教程,并修改了部分代碼實現:

WebUploader--基于SpringBoot搭建,Java文件上傳下載高階實戰

本文代碼已上傳至GitHub:

BurstDownload

到此這篇關于SpringBoot大文件RestTemplate下載解決方案的文章就介紹到這了,更多相關SpringBoot RestTemplate下載內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/yif0118/p/15456666.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 村上里沙40分钟在线观看 | 久久成人免费大片 | 香蕉久久夜色精品国产尤物 | 亚洲欧美一 | 闺蜜调教我做她的脚奴 | 亚洲娇小性hd | 麻豆视频入口 | 九九热免费在线观看 | 免费二级毛片免费完整视频 | 视频一区国产精戏刘婷 | 性色生活片在线观看 | 人阁色第四影院在线观看 | 精品国产线拍大陆久久尤物 | 明星ai人脸替换脸忘忧草 | 青视频在线 | 草草草视频 | 欧美亚洲国产精品久久久 | 成人精品一区二区三区 | 99青青青精品视频在线 | 欧美美女一区二区三区 | 色老板在线免费观看 | 日韩欧美综合在线二区三区 | 女同性互吃奶乳免费视频 | 青草视频免费观看在线观看 | 国产精品香蕉在线观看不卡 | 女人pp被扒开流水了 | 15一16japanese破| 青青草99 | 午夜片无码区在线观看 | 沟厕okn系列在线播放 | 欧美性4khd720 | 男人插曲女人身体 | 欧美午夜网站 | 精品suv一区二区三区 | 成人亚洲精品一区 | 91免费永久国产在线观看 | 欧美日韩精彩视频 | 国产爽视频 | 9l国产精品久久久久麻豆 | 亚洲上最大成网人站4438 | 五月最新商场女厕所高跟嘘嘘 |