chinabugotech/hutool · error · IORuntimeException

Can't compare directories, only files

Error message

Can't compare directories, only files

What it means

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).

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java:1498

	 * @param file2 文件2
	 * @return 两个文件内容一致返回true,否则false
	 * @throws IORuntimeException IO异常
	 * @since 4.0.6
	 */
	public static boolean contentEquals(File file1, File file2) throws IORuntimeException {
		boolean file1Exists = file1.exists();
		if (file1Exists != file2.exists()) {
			return false;
		}

		if (false == file1Exists) {
			// 两个文件都不存在,返回true
			return true;
		}

		if (file1.isDirectory() || file2.isDirectory()) {
			// 不比较目录
			throw new IORuntimeException("Can't compare directories, only files");
		}

		if (file1.length() != file2.length()) {
			// 文件长度不同
			return false;
		}

		if (equals(file1, file2)) {
			// 同一个文件
			return true;
		}

		InputStream input1 = null;
		InputStream input2 = null;
		try {
			input1 = getInputStream(file1);
			input2 = getInputStream(file2);
			return IoUtil.contentEquals(input1, input2);

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Guard both arguments with FileUtil.isFile() before calling.
  2. Filter directory listings to regular files before comparing.
  3. If you need directory comparison, implement your own recursive walk comparing file sets.

Example fix

// before
boolean same = FileUtil.contentEquals(a, b); // throws if either is a dir

// after
if (FileUtil.isFile(a) && FileUtil.isFile(b)) {
    boolean same = FileUtil.contentEquals(a, b);
}
Defensive patterns

Strategy: validation

Validate before calling

if (FileUtil.isFile(file1) && FileUtil.isFile(file2)) {
    return FileUtil.contentEquals(file1, file2);
}
return false;

Type guard

static boolean bothRegularFiles(File a, File b) {
    return a != null && b != null && a.isFile() && b.isFile();
}

Try / catch

try {
    return FileUtil.contentEquals(a, b);
} catch (IORuntimeException e) {
    // one of them was a directory: skip or compare differently
}

Prevention

When it happens

Trigger: Calling FileUtil.contentEquals where file1 or file2 is an existing directory.

Common situations: Comparing a directory against a file; iterating a folder's children and passing a subdirectory by accident; user input that resolves to a folder.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/54a7a305595b3d6d. Report an issue: GitHub.