我正在以大约10b到16000b的块写入文件,当突然每个块被切断大约4050字节(具体地,4050,4051和4074字节,按此顺序)。这意味着后续写入将覆盖应该写入的数据,从而弄乱我的数据。任何4050b以下的大块都写得很好。
不幸的是,我无法重现它。我所拥有的只是混乱的文件,所以我正在调试寻找可能导致这种情况的东西。
调试它,我意识到c的write()函数在引擎盖下调用(这是Java代码,FileChannel.write(),但是标准库调用c的write并且只检查写入的字节> 0),并且它的文档并不能保证它会写出所有要求的数据,只是它会告诉你写了多少。
我不检查在Java土地上写回的字节(但我确实得到它,函数签名几乎完全相同),所以修复很简单。但是,由于我无法重现这一点,我不知道我已经解决了实际问题。因此,我希望有些c guru可以告诉我,我冒烟,或者有合法的情况,write()一次不能写超过4050个字节。
这是在64位Linux内核版本3.0.0-26上运行。
编辑:根据以下评论展开:
我正在写一个普通的文件系统文件。我不确定在这种情况下非阻塞意味着什么,我没有使用回调或任何东西,但明确地告诉操作系统没有为每个块执行刷新到磁盘。该文件使用Java的RandomAccessFile,'rw'模式打开。
答案 0 :(得分:5)
来自man 2 write
:
The number of bytes written may be less than count if, for example,
there is insufficient space on the underlying physical medium, or the
RLIMIT_FSIZE resource limit is encountered (see setrlimit(2)), or the
call was interrupted by a signal handler after having written less than
count bytes. (See also pipe(7).)
来自man 2 setrlimit
:
RLIMIT_FSIZE
The maximum size of files that the process may create. Attempts
to extend a file beyond this limit result in delivery of a
SIGXFSZ signal. By default, this signal terminates a process,
but a process can catch this signal instead, in which case the
relevant system call (e.g., write(2), truncate(2)) fails with
the error EFBIG.
使用以下命令可以看到这些限制:
ulimit -Sf
ulimit -Hf
或者使用这个C程序:
#include <stdio.h>
#include <errno.h>
#include <sys/resource.h>
int main()
{
struct rlimit rl;
if (getrlimit(RLIMIT_FSIZE, &rl) == 0) {
printf("%d %d\n", rl.rlim_cur, rl.rlim_max);
} else {
fprintf(stderr, "error: %d\n", errno);
}
return 0;
}
答案 1 :(得分:4)
从Linux程序员手册,写入(1):“write()将最多计数字节写入文件......”
写入多少取决于您要写入的内容以及是否使用同步写入。
E.g。如果它是一个管道,就像一个套接字,你不能写一个管道/套接字缓冲区满(在同步模式下:比缓冲区中的可用内容更多)。
答案 2 :(得分:3)
重现问题的最简单方法是让消费者放慢速度。当调用write()时,这将导致发送缓冲区几乎已满,这意味着不能写入您提供的所有数据。您可以减少发送和接收器缓冲区大小,以使此问题更加明显。