1

我正在以大约 10b 到 16 000b 的块写入文件,突然每个块在大约 4050 字节处被截断(特别是 4050、4051 和 4074 字节,按此顺序)。这意味着后续的写入将覆盖本应写入的数据,从而弄乱我的数据。任何低于 4050b 的块都可以正常写出。

不幸的是,我无法重现它。我所拥有的只是混乱的文件,所以我正在调试寻找会导致这种情况的东西。

调试它,我意识到 c 的 write() 函数在后台被调用(这是 Java 代码 FileChannel.write(),但标准库调用 c 的 write 并且只检查写入的字节 > 0),并且它的文档不保证它会写出所有要求的数据,只会告诉你写了多少。

我不检查在 Java 领域写回的字节(但我确实明白了,函数签名几乎完全相同),所以修复非常简单。但是,由于我无法重现这一点,我不知道我已经解决了实际问题。因此,因此我希望某些 c 大师可以告诉我,我正在吸烟,或者在某些合法情况下 write() 一次无法写入超过 4050 个字节。

这是在 64 位 Linux 内核版本 3.0.0-26 上运行的。

编辑:根据以下评论进行扩展:

我正在写入一个普通的文件系统文件。我不确定在这种情况下非阻塞意味着什么,我没有使用回调或任何东西,但是对于每个块都没有明确告诉操作系统刷新到磁盘。该文件使用 Java 的 RandomAccessFile 'rw' 模式打开。

4

3 回答 3

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;
}
于 2012-10-09T08:34:29.147 回答
4

来自 Linux Programmer's Manual,在 write(1) 上:“write() 最多写入 count 个字节到文件...”

写入多少取决于您要写入的内容以及您是否使用同步写入。

例如,如果它是一个管道或一个套接字,则您不能写入超过一个管道/套接字缓冲区已满(在同步模式下:超过缓冲区中可用的内容)。

于 2012-10-09T08:36:56.067 回答
2

重现问题的最简单方法是让消费者缓慢。当您调用 write() 时,这将导致发送缓冲区几乎已满,这意味着并非您提供的所有数据都可以写入。您可以减少发送和接收缓冲区的大小以使此问题更加明显。

于 2012-10-09T08:31:41.563 回答