{"record":{"id":"54a7a305595b3d6d","repo":"chinabugotech/hutool","slug":"can-t-compare-directories-only-files","errorCode":null,"errorMessage":"Can't compare directories, only files","messagePattern":"Can't compare directories, only files","errorType":"exception","errorClass":"IORuntimeException","httpStatus":null,"severity":"error","filePath":"hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java","lineNumber":1498,"sourceCode":"\t * @param file2 文件2\n\t * @return 两个文件内容一致返回true，否则false\n\t * @throws IORuntimeException IO异常\n\t * @since 4.0.6\n\t */\n\tpublic static boolean contentEquals(File file1, File file2) throws IORuntimeException {\n\t\tboolean file1Exists = file1.exists();\n\t\tif (file1Exists != file2.exists()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (false == file1Exists) {\n\t\t\t// 两个文件都不存在，返回true\n\t\t\treturn true;\n\t\t}\n\n\t\tif (file1.isDirectory() || file2.isDirectory()) {\n\t\t\t// 不比较目录\n\t\t\tthrow new IORuntimeException(\"Can't compare directories, only files\");\n\t\t}\n\n\t\tif (file1.length() != file2.length()) {\n\t\t\t// 文件长度不同\n\t\t\treturn false;\n\t\t}\n\n\t\tif (equals(file1, file2)) {\n\t\t\t// 同一个文件\n\t\t\treturn true;\n\t\t}\n\n\t\tInputStream input1 = null;\n\t\tInputStream input2 = null;\n\t\ttry {\n\t\t\tinput1 = getInputStream(file1);\n\t\t\tinput2 = getInputStream(file2);\n\t\t\treturn IoUtil.contentEquals(input1, input2);","sourceCodeStart":1480,"sourceCodeEnd":1516,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java#L1480-L1516","documentation":"FileUtil.contentEquals(File, File) compares two files byte-for-byte. It deliberately refuses directories because directory content comparison is undefined, throwing IORuntimeException(\"Can't compare directories, only files\") if either argument is a directory (both must exist to reach this check).","triggerScenarios":"Calling FileUtil.contentEquals where file1 or file2 is an existing directory.","commonSituations":"Comparing a directory against a file; iterating a folder's children and passing a subdirectory by accident; user input that resolves to a folder.","solutions":["Guard both arguments with FileUtil.isFile() before calling.","Filter directory listings to regular files before comparing.","If you need directory comparison, implement your own recursive walk comparing file sets."],"exampleFix":"// before\nboolean same = FileUtil.contentEquals(a, b); // throws if either is a dir\n\n// after\nif (FileUtil.isFile(a) && FileUtil.isFile(b)) {\n    boolean same = FileUtil.contentEquals(a, b);\n}","handlingStrategy":"validation","validationCode":"if (FileUtil.isFile(file1) && FileUtil.isFile(file2)) {\n    return FileUtil.contentEquals(file1, file2);\n}\nreturn false;","typeGuard":"static boolean bothRegularFiles(File a, File b) {\n    return a != null && b != null && a.isFile() && b.isFile();\n}","tryCatchPattern":"try {\n    return FileUtil.contentEquals(a, b);\n} catch (IORuntimeException e) {\n    // one of them was a directory: skip or compare differently\n}","preventionTips":["Filter to regular files before comparing contents.","Skip directories when walking and comparing directory trees.","Resolve and check both paths exist as files before the call."],"tags":["io","file","comparison","validation"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}