You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解析Apache日志:统计总传输字节数遇Java代码问题求助

问题

现有如下Apache日志文件:

64.242.88.10 - - [08/Mar/2004:07:56:34 -0800] "GET /twiki/bin/search/Main/SearchResult?scope=text&regex=on&search=Web%20*Index[^A-Za-z] HTTP/1.1" 200 4163

64.242.88.10 - - [08/Mar/2004:08:04:46 -0800] "GET /SpamAssassin.html HTTP/1.1" 200 7368
p5083cd5d.dip0.t-ipconnect.de - - [08/Mar/2004:08:09:32 -0800] "GET /SpamAssassin.html HTTP/1.0" 200 7368

64.242.88.10 - - [08/Mar/2004:08:12:50 -0800] "GET /twiki/bin/view/TWiki/ChangePassword?rev=r1.6 HTTP/1.1" 200 5181

64.242.88.10 - - [08/Mar/2004:08:14:15 -0800] "GET /twiki/bin/edit/TWiki/HaroldGottschalk?t=1078717948 HTTP/1.1" 401 12846

64.242.88.10 - - [08/Mar/2004:08:15:21 -0800] "GET /twiki/bin/edit/Main/Expand_owner_alias?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12846

需要提取每行末尾的字节数并求和,当前Java代码如下:

static String logEntryFormat = "^(\\S+) (\\S+) (\\S+) \\[(.*?)\\] \"(.*?)\" (\\S+) (\\S+)( \"(.*?)\" \"(.*?)\")?";

public static void countTotalBytes() throws IOException {

    // First read file into an arrayList
    Scanner scanner = new Scanner(accessLog);
    ArrayList<String> stringList = new ArrayList<String>();
    while (scanner.hasNextLine()){
    stringList.add(scanner.nextLine());

    scanner.close();

    //Convert to string
    String listString = String.join(" ", stringList);

    Pattern findBytes = Pattern.compile(logEntryFormat);
    Matcher matchBytes = findBytes.matcher(listString);

    // Test
    if(matchBytes.matches()) {
    System.out.println(matchBytes.group(7));
    }
}

目前仅输出字节值"7368",无法计算总和,需要修正代码。

解决方案

代码核心问题

  1. Scanner提前关闭:scanner.close()写在while循环内部,导致仅读取第一行日志后就关闭了Scanner,后续日志行无法读取。
  2. 错误拼接日志行:将所有日志行用空格拼接成单个字符串,再用matches()匹配——该方法要求正则匹配整个字符串,因此只能得到一次匹配结果,无法遍历所有行的字节数。
  3. 循环语法错误:while循环缺少闭合大括号,逻辑结构混乱。

修正后的代码

import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ApacheLogByteCounter {
    static String logEntryFormat = "^(\\S+) (\\S+) (\\S+) \\[(.*?)\\] \"(.*?)\" (\\S+) (\\S+)( \"(.*?)\" \"(.*?)\")?$";

    public static void countTotalBytes() throws IOException {
        File accessLog = new File("你的日志文件路径"); // 替换为实际日志文件路径
        Scanner scanner = new Scanner(accessLog);
        int totalBytes = 0;
        Pattern pattern = Pattern.compile(logEntryFormat);

        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            // 跳过空行
            if (line.isEmpty()) {
                continue;
            }
            Matcher matcher = pattern.matcher(line);
            if (matcher.matches()) {
                try {
                    // 提取字节数并累加
                    int bytes = Integer.parseInt(matcher.group(7));
                    totalBytes += bytes;
                } catch (NumberFormatException e) {
                    // 处理非数字的异常情况(如日志中用"-"表示无字节数据)
                    System.err.println("无法解析字节数: " + matcher.group(7));
                }
            } else {
                System.err.println("不匹配的日志行: " + line);
            }
        }
        scanner.close();
        System.out.println("总传输字节数: " + totalBytes);
    }

    public static void main(String[] args) {
        try {
            countTotalBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

关键优化点

  • 逐行处理:每次读取一行日志单独匹配正则,确保每行字节数都能被提取。
  • 跳过空行:过滤日志中的空行,避免无效匹配。
  • 异常处理:兼容字节数字段非整数的情况(部分Apache日志用"-"代替0字节)。
  • 正确管理资源:Scanner在循环结束后关闭,保证所有日志行都被读取。

给定日志的计算结果

代入提供的日志,总传输字节数为:4163 + 7368 + 7368 + 5181 + 12846 + 12846 = 49772

内容的提问来源于stack exchange,提问作者4K4K1N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:25:56