Java 实例 – 获取远程文件大小(长文解析)

Java 实例 – 获取远程文件大小:从入门到实战

在日常开发中,我们经常会遇到需要判断远程文件大小的场景。比如,用户上传一个大文件前,先预估下载时间;又或者在后台任务中,根据文件大小决定是否启用压缩或分块处理。这些操作背后,都离不开一个基础能力:获取远程文件的大小

本文将带你通过一个完整的 Java 实例,一步步掌握如何通过代码实现“获取远程文件大小”这一常见需求。无论你是刚接触 Java 的初学者,还是有一定经验的中级开发者,都能从中收获实用技巧。


为什么需要获取远程文件大小?

想象一下,你正在开发一个文件管理工具。用户从网络上粘贴一个链接,希望你判断这个文件有多大。如果直接下载,可能浪费带宽和时间;如果先查询大小,就能提前告知用户“这个文件是 200MB,预计下载时间 3 分钟”,用户体验立刻提升。

这正是“获取远程文件大小”的价值所在。它不是单纯的“读取一个数字”,而是对网络通信、HTTP 协议和异常处理能力的综合考验。


使用 HTTP HEAD 请求获取文件大小

要获取远程文件大小,最高效的方式是使用 HTTP 的 HEAD 请求。与 GET 请求不同,HEAD 只获取响应头信息,不下载文件体。这就像你去邮局寄包裹,只需要知道包裹的重量,而不需要打开它。

什么是 HTTP HEAD 请求?

HTTP 协议中,HEAD 是一种请求方法,用于获取资源的元信息,比如:

  • 文件大小(Content-Length)
  • 内容类型(Content-Type)
  • 最后修改时间(Last-Modified)

它与 GET 的区别在于:不返回响应体,只返回响应头。这使得它非常轻量,适合用于“探查”资源。

Java 中如何发送 HEAD 请求?

Java 提供了标准的 java.net.HttpURLConnection 类,可以用来发送任意 HTTP 请求。我们通过它发送 HEAD 请求,获取文件大小。

以下是完整的代码示例:

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class RemoteFileSizeFetcher {

    /**
     * 获取远程文件大小
     * @param urlString 远程文件的 URL 地址
     * @return 文件大小(字节),若失败返回 -1
     */
    public static long getRemoteFileSize(String urlString) {
        HttpURLConnection connection = null;
        try {
            // 1. 创建 URL 对象
            URL url = new URL(urlString);

            // 2. 打开连接
            connection = (HttpURLConnection) url.openConnection();

            // 3. 设置请求方法为 HEAD
            connection.setRequestMethod("HEAD");

            // 4. 设置请求头,避免被服务器拒绝
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");

            // 5. 建立连接
            connection.connect();

            // 6. 获取响应码
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK && responseCode != HttpURLConnection.HTTP_PARTIAL) {
                System.out.println("请求失败,响应码:" + responseCode);
                return -1;
            }

            // 7. 从响应头中获取 Content-Length 字段
            String contentLength = connection.getHeaderField("Content-Length");
            if (contentLength == null || contentLength.isEmpty()) {
                System.out.println("服务器未返回文件大小信息");
                return -1;
            }

            // 8. 解析并返回文件大小(单位:字节)
            return Long.parseLong(contentLength);

        } catch (IOException e) {
            System.err.println("网络请求异常:" + e.getMessage());
            return -1;
        } finally {
            // 9. 关闭连接,释放资源
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    // 主方法用于测试
    public static void main(String[] args) {
        String url = "https://example.com/sample.zip";

        long size = getRemoteFileSize(url);
        if (size > 0) {
            System.out.println("远程文件大小:" + size + " 字节");
            System.out.println("约 " + (size / 1024.0 / 1024.0) + " MB");
        } else {
            System.out.println("获取文件大小失败");
        }
    }
}

代码逐行解析

  • new URL(urlString):将字符串转为 URL 对象,这是所有网络请求的基础。
  • url.openConnection():打开一个连接,返回 HttpURLConnection 实例。
  • setRequestMethod("HEAD"):明确指定使用 HEAD 方法,只获取头信息。
  • setRequestProperty("User-Agent", ...):设置请求头,模拟浏览器行为,防止被服务器拒绝(很多服务器会拦截无 User-Agent 的请求)。
  • connect():真正建立连接,此时请求被发送。
  • getResponseCode():获取服务器返回的状态码,200 表示成功。
  • getHeaderField("Content-Length"):从响应头中提取文件大小。这是关键一步。
  • Long.parseLong(contentLength):将字符串转为数值,单位是字节。
  • connection.disconnect():关闭连接,释放系统资源。

常见问题与解决方案

在实际使用中,你可能会遇到以下几种情况:

1. 服务器未返回 Content-Length

有些服务器(尤其是流式服务或 CDN)不会在响应头中返回 Content-Length。这时,你只能通过下载一小部分数据来估算大小,但这属于进阶技巧,不在本篇范围。

2. 服务器返回 301/302 重定向

如果 URL 重定向到另一个地址,HEAD 请求会自动跟随(除非你关闭自动重定向),但需注意最终目标是否支持 HEAD。

3. 网络超时或连接失败

建议设置超时时间,防止程序卡死。可以添加:

connection.setConnectTimeout(5000);  // 连接超时 5 秒
connection.setReadTimeout(10000);    // 读取超时 10 秒

使用 Apache HttpClient(更推荐的方案)

虽然 HttpURLConnection 是 Java 标准库,但功能较原始。对于更复杂的网络请求,建议使用 Apache HttpClient,它更强大、更易用。

添加依赖(Maven)

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version>
</dependency>

使用 HttpClient 发送 HEAD 请求

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class HttpClientRemoteFileSize {

    public static long getRemoteFileSize(String urlString) {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            // 1. 创建 HEAD 请求
            HttpHead headRequest = new HttpHead(urlString);

            // 2. 设置 User-Agent 头
            headRequest.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");

            // 3. 执行请求
            HttpResponse response = client.execute(headRequest);

            // 4. 获取状态码
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                System.out.println("请求失败,状态码:" + statusCode);
                return -1;
            }

            // 5. 从响应头中获取 Content-Length
            String contentLength = response.getFirstHeader("Content-Length") != null
                    ? response.getFirstHeader("Content-Length").getValue()
                    : null;

            if (contentLength == null || contentLength.isEmpty()) {
                System.out.println("服务器未返回文件大小");
                return -1;
            }

            return Long.parseLong(contentLength);

        } catch (Exception e) {
            System.err.println("请求异常:" + e.getMessage());
            return -1;
        }
    }

    public static void main(String[] args) {
        String url = "https://example.com/sample.zip";
        long size = getRemoteFileSize(url);
        if (size > 0) {
            System.out.println("远程文件大小:" + size + " 字节");
        } else {
            System.out.println("获取失败");
        }
    }
}

优势对比

特性 HttpURLConnection Apache HttpClient
使用复杂度 较高 较低
超时设置 手动配置 灵活
重定向处理 自动 可配置
异常处理 需手动捕获 更健壮

实际应用场景

  • 文件下载器:预估下载时间,优化用户体验。
  • 云存储管理:判断是否需要分块上传。
  • 资源监控系统:定期检查远程资源大小变化。
  • 备份工具:判断文件是否已存在且大小一致。

总结

通过本文,你已经掌握了“Java 实例 – 获取远程文件大小”的完整实现方案。无论是使用标准库 HttpURLConnection,还是更强大的 Apache HttpClient,核心思想都是:利用 HTTP HEAD 请求,仅获取响应头中的 Content-Length 字段

记住几个关键点:

  • 不要使用 GET 请求下载整个文件来获取大小,效率极低。
  • 使用 HEAD 请求,只获取头信息,轻量高效。
  • 设置合理的请求头(尤其是 User-Agent)。
  • 做好异常处理和资源释放。

这个技能虽然看似简单,却是构建网络应用时不可或缺的一环。当你能稳定获取远程文件大小时,你就离“专业开发者”又近了一步。

下次你再遇到“这个文件有多大?”的问题,别再手动查了——用代码,一分钟搞定。