掌握 Java 文件下载:原理、方法与实践

掌握 Java 文件下载:原理、方法与实践

文章引言

在数字化时代,文件下载是网站和应用的一个基础功能,非常重要。Java 开发的人经常要实现文件下载。本文讲 Java 文件下载,有不同方法、问题和答案。帮开发者学这个,还能让百度搜到,提高排名。

Java 文件下载的基础原理

Java 文件下载就是把服务器上文件通过网络弄到客户端。这过程里,要从服务器读文件内容,再用输出流发给客户端。常用的Java的类有

FileInputStream

OutputStream

等类,提供了文件读写、传输的基本功能7911。

Java 文件下载的实现方式

直接使用超链接

最简单下载文件就是直接用HTML

<a>

标签将

href

属性就是指导向那个资源文件。例如:

<a href="path/to/your/file.pdf"> 下载文件</a> 

但这种法有限制,下载没控制,谁都能下载。如果文件浏览器能打开,它就直接开了,不会下载成附件9。

通过 Servlet 实现下载

这是更方便的下载方式,能管下载,比如验证啊,文件类型处理。这是一个代码的小例子

import java.io.FileInputStream;  

import java.io.IOException;  

import java.io.InputStream;  

import java.io.OutputStream;  

import java.net.URLEncoder;  

import javax.servlet.ServletException;  

import javax.servlet.annotation.WebServlet;  

import javax.servlet.http.HttpServlet;  

import javax.servlet.http.HttpServletRequest;  

import javax.servlet.http.HttpServletResponse;  

@WebServlet(name = "DownServlet", urlPatterns = "/DownServlet")public class DownServlet extends HttpServlet { 

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

        doPost(req, resp); 

    } 

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

        req.setCharacterEncoding("UTF-8");  

        String name = req.getParameter("name");  // 获取要下载的文件名         // 第一步:设置响应类型         resp.setContentType("application/force-download");  // 应用程序强制下载         // 第二步:读取文件         String path = getServletContext.getRealPath("/up/" + name); 

        InputStream in = new FileInputStream(path); 

        // 设置响应头,对文件进行 url 编码         name = URLEncoder.encode(name,  "UTF-8"); 

        resp.setHeader("Content-Disposition",  "attachment;filename=" + name); 

        resp.setContentLength(in.available);  

        // 第三步:开始复制         OutputStream out = resp.getOutputStream;  

        byte[] b = new byte[1024]; 

        int len = 0; 

        while ((len = in.read(b))  != -1) { 

            out.write(b,  0, len); 

        } 

        out.flush;  

        out.close;  

        in.close;  

    } 

上述代码里,先设了响应类型

application/force-download

请保证文件以下载附件方式得到。然后读取文件,设响应头,文件名URL编码下,避免乱码。最后文件内容通过循环写入了输出流,下载完成9。

多线程下载

大文件下载,多线程会让下载变得更快。原理是文件被分成好多块,然后每个线程下载一块,再把它们合起来成一个文件。这是一个多线程下载的思路

import java.io.*;  

import java.net.HttpURLConnection;  

import java.net.URL;  

class DownloadThread extends Thread { 

    private String url; 

    private long start; 

    private long end; 

掌握 Java 文件下载:原理、方法与实践

    private String filePath; 

    public DownloadThread(String url, long start, long end, String filePath) { 

        this.url  = url; 

        this.start  = start; 

        this.end  = end; 

        this.filePath  = filePath; 

    } 

    @Override    public void run { 

        try { 

            URL fileUrl = new URL(url); 

            HttpURLConnection conn = (HttpURLConnection) fileUrl.openConnection;  

            conn.setRequestProperty("Range",  "bytes=" + start + "-" + end); 

            InputStream in = conn.getInputStream;  

            RandomAccessFile raf = new RandomAccessFile(filePath, "rw"); 

            raf.seek(start);  

            byte[] buffer = new byte[1024]; 

            int len; 

            while ((len = in.read(buffer))  != -1) { 

                raf.write(buffer,  0, len); 

            } 

            raf.close;  

            in.close;  

        } catch (IOException e) { 

            e.printStackTrace;  

        } 

    } 

public class MultiThreadDownload { 

    public static void main(String[] args) { 

        String url = "http://example.com/largefile.zip";  

        String filePath = "downloadedfile.zip";  

        int threadCount = 5; 

        try { 

            URL fileUrl = new URL(url); 

            HttpURLConnection conn = (HttpURLConnection) fileUrl.openConnection;  

            long fileLength = conn.getContentLengthLong;  

            long blockSize = fileLength / threadCount; 

            for (int i = 0; i < threadCount; i++) { 

                long start = i * blockSize; 

                long end = (i == threadCount - 1) ? fileLength - 1 : start + blockSize - 1; 

                DownloadThread thread = new DownloadThread(url, start, end, filePath); 

                thread.start;  

            } 

        } catch (IOException e) { 

            e.printStackTrace;  

        } 

    } 

这个例子里,做了很多个

DownloadThread

线程,各自负责文件下载的某一块。通过设置

Range

请求头能指定线程下载范围,把各段下载内容合并到一个文件7。

Java 文件下载的常见问题及解决方案

中文乱码问题

处理中文文件名时,可能有乱码出现。解决方式是文件名URL编码,且设好响应字符编码。例如:

String name = "中文文件名.txt"; 

name = URLEncoder.encode(name,  "UTF-8"); 

resp.setHeader("Content-Disposition",  "attachment;filename=" + name); 

resp.setCharacterEncoding("UTF-8");  

下载文件浏览器直接打开问题

为了文件下载后打不开,设个响应类型就行

application/force-download

掌握 Java 文件下载:原理、方法与实践

,并在响应头中添加

attachment

标识。例如:

resp.setContentType("application/force-download");  

resp.setHeader("Content-Disposition",  "attachment;filename=" + name); 

从 URI 下载文件问题

下载文件时,用 URI 可能会找不到文件,或者出现协议不对的问题。可以使用

HttpClient

使用工具下载URI。例如:

import org.apache.commons.httpclient.HttpClient;  

import org.apache.commons.httpclient.HttpException;  

import org.apache.commons.httpclient.methods.GetMethod;  

import java.io.*;  

public class DownloadFromURI { 

    public static void main(String[] args) { 

        String path = "http://example.com/file.txt";  

        String name = "downloaded.txt";  

        HttpClient httpClient = new HttpClient; 

        GetMethod getMethod = new GetMethod(path); 

        BufferedInputStream bis = null; 

        BufferedOutputStream bos = null; 

        OutputStream fos = null; 

        InputStream fis = null; 

        try { 

            // 使用系统提供的默认的恢复策略             getMethod.getParams.setParameter(org.apache.commons.httpclient.params.HttpMethodParams.RETRY_HANDLER,  

                    new org.apache.commons.httpclient.DefaultHttpMethodRetryHandler);  

            int statusCode = httpClient.executeMethod(getMethod);  

            fis = getMethod.getResponseBodyAsStream;  

            bis = new BufferedInputStream(fis); 

            fos = new FileOutputStream(name); 

            bos = new BufferedOutputStream(fos); 

            int bytesRead = 0; 

            byte[] buffer = new byte[8192]; 

            while ((bytesRead = bis.read(buffer,  0, 8192)) != -1) { 

                bos.write(buffer,  0, bytesRead); 

            } 

            bos.flush;  

        } catch (HttpException e) { 

            System.out.println("Please  check your provided http address!"); 

        } catch (IOException e) { 

            e.printStackTrace;  

        } finally { 

            try { 

                if (fis != null) fis.close;  

                if (bis != null) bis.close;  

                if (fos != null) fos.close;  

                if (bos != null) bos.close;  

                getMethod.releaseConnection;  

            } catch (IOException e) { 

                e.printStackTrace;  

            } 

        } 

    } 

总结

Java文件下载是个常用功能,开发者可根据需求选方法。读这文章,我们懂了超链接下载、Servlet下载,还有多线程下载。也知道了咋解决常见问题。实际开发时,要看情况优化和扩展,提高下载速度和用户感觉。希望本文对Java开发人员在下载文件时有帮助。

文章优化建议

关键字:文章里常提到“java 文件下载”,还有“Servlet 下载”、“多线程”、“乱码处理”等,能帮文章在搜索引擎上更靠前。

内容质量高,文章很详细,给了很多代码示例和问题解决方法,很实用专业,满足百度搜索结果标准。

文章结构很明了,用了总分总方式。每部分都有标题,很清楚,读者好读,也助搜索引擎索引。


《掌握 Java 文件下载:原理、方法与实践》.doc
将本文下载保存,方便收藏和打印
下载文档