chinabugotech/hutool · error · IOException
File length is [{}] but read [{}]!
Error message
File length is [{}] but read [{}]! What it means
After allocating a buffer of exactly file.length() bytes and calling FileInputStream.read(bytes), Hutool verifies that the number of bytes actually read equals the file length. If readLength < len it throws an IOException with the formatted length/read mismatch, which the surrounding catch (Exception e) wraps into IORuntimeException. This guards against three root causes: the file was truncated or rewritten between the length() call and the read (TOCTOU), the filesystem reports an inaccurate length (special files such as /proc/*, named pipes, device files), or a single read() returned early without filling the buffer.
Source
Thrown at hutool-core/src/main/java/cn/hutool/core/io/file/FileReader.java:126
* 文件的长度不能超过 {@link Integer#MAX_VALUE}
*
* @return 字节码
* @throws IORuntimeException IO异常
*/
public byte[] readBytes() throws IORuntimeException {
long len = file.length();
if (len >= Integer.MAX_VALUE) {
throw new IORuntimeException("File is larger then max array size");
}
byte[] bytes = new byte[(int) len];
FileInputStream in = null;
int readLength;
try {
in = new FileInputStream(file);
readLength = in.read(bytes);
if(readLength < len){
throw new IOException(StrUtil.format("File length is [{}] but read [{}]!", len, readLength));
}
} catch (Exception e) {
throw new IORuntimeException(e);
} finally {
IoUtil.close(in);
}
return bytes;
}
/**
* 读取文件内容
*
* @return 内容
* @throws IORuntimeException IO异常
*/
public String readString() throws IORuntimeException{
return new String(readBytes(), this.charset);View on GitHub (pinned to 8870454b2a)
Solutions
- Ensure the file is not concurrently modified during the read (lock it, or copy it to a stable temp file first).
- For special/pseudo files, stream with getInputStream()/readLines() instead of readBytes(), since their reported length is unreliable.
- Wait until the file is fully written (download complete / writer closed) before reading.
- If transient, retry the read once the file stabilizes; on persistent mismatch, inspect getCause() of the IORuntimeException for the underlying IOException.
Example fix
// before: assumes file is stable and length() is accurate
byte[] data = FileReader.create(file).readBytes();
// after: stream from a possibly-unstable / special file
try (InputStream in = FileReader.create(stableCopy).getInputStream()) {
// read incrementally; never trusts a single length() value
byte[] chunk = in.readNBytes(8192);
} Defensive patterns
Strategy: try-catch
Validate before calling
// For special/proc files, skip readBytes entirely:
if (file.getPath().startsWith("/proc") || file.getPath().startsWith("/sys")
|| !file.isFile()) {
// stream instead; do NOT trust file.length()
return;
}
// For regular files that may be concurrently written, copy to a stable temp first:
Path tmp = Files.createTempFile("read-", ".tmp");
try {
Files.copy(file.toPath(), tmp, StandardCopyOption.REPLACE_EXISTING);
byte[] data = FileReader.create(tmp.toFile()).readBytes();
} finally {
Files.deleteIfExists(tmp);
} Type guard
boolean lengthIsReliable(File f) {
if (f == null || !f.isFile()) return false;
String p = f.getPath();
// pseudo-filesystems report inaccurate lengths
return !p.startsWith("/proc") && !p.startsWith("/sys") && !p.startsWith("/dev");
} Try / catch
try {
byte[] data = FileReader.create(f).readBytes();
} catch (IORuntimeException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException && String.valueOf(cause.getMessage())
.contains("File length is") && cause.getMessage().contains("but read")) {
// likely truncation/short-read: stream instead, or retry after stabilization
try (InputStream in = new BufferedInputStream(new FileInputStream(f))) {
// consume fully with a read-loop
}
} else {
throw e;
}
} Prevention
- Avoid concurrent truncation/rewrite of files you are reading with readBytes().
- Never call readBytes() on /proc, /sys, /dev, pipes, or sockets.
- Copy actively-written files to a temp location before reading them whole.
- Wait for download/writer completion before reading.
- Prefer streaming reads when the file's lifetime is not under your control.
When it happens
Trigger: Calling FileReader.readBytes() (directly or via readString()) when: the file is concurrently modified/truncated between file.length() and in.read(); the path points at a special/proc or pseudo-file whose size() is wrong; FileInputStream.read(byte[]) returns fewer bytes than requested in a single invocation on some network/overlay filesystems; the file is actively being written/downloaded and shrinks mid-read.
Common situations: Concurrent log rotation truncating a file during read; reading Linux pseudo-files (/proc, /sys) that report 0 or stale lengths; reading a file still being streamed/downloaded; race conditions in multi-process pipelines; FUSE/network filesystems where read() may short-return.
Related errors
- Src [{}] is a directory but dest [{}] is a file!
- File is larger then max array size
- File not exist: {}
- Not a file: {}
- TTS请求失败:
AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14).
Data as JSON: /api/errors/f8ae1e63428211e8.
Report an issue: GitHub.