解析Apache日志:统计总传输字节数遇Java代码问题求助
问题
现有如下Apache日志文件:
64.242.88.10 - - [08/Mar/2004:07:56:34 -0800] "GET /twiki/bin/search/Main/SearchResult?scope=text®ex=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",无法计算总和,需要修正代码。
解决方案
代码核心问题
- Scanner提前关闭:
scanner.close()写在while循环内部,导致仅读取第一行日志后就关闭了Scanner,后续日志行无法读取。 - 错误拼接日志行:将所有日志行用空格拼接成单个字符串,再用
matches()匹配——该方法要求正则匹配整个字符串,因此只能得到一次匹配结果,无法遍历所有行的字节数。 - 循环语法错误:
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
相关产品推荐
相关产品推荐

