1

我试图lseek()在创建所需大小的文件时真正理解使用。所以我编写了这段代码,其唯一目标是创建一个输入中给定大小的文件

运行例如:

$ ./lseek_test myFile 5

我希望它创建一个名为myFile5 个字节的文件,其最后一个字节被数字 5 占据。我得到的是一个我什至无法访问的文件。怎么了?我是否错误地解释了lseek()用法?

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

#define abort_on_error(cond, msg) do {\
    if(cond) {\
        int _e = errno;\
        fprintf(stderr, "%s (%d)\n", msg, _e);\
        exit(EXIT_FAILURE);\
    }\
} while(0)

/* Write an integer with error control on the file */
void write_int(int fd, int v) {
    ssize_t c = write(fd, &v, sizeof(v));
    if (c == sizeof(v))
        return;
    abort_on_error(c == -1 && errno != EINTR, "Error writing the output file");
    abort_on_error(1, "Write operation interrupted, aborting");
}

int main(int argc, char *argv[]) {
    // Usage control
    abort_on_error(argc != 3, "Usage: ./lseek_test <FileName> <FileSize>");

    // Parsing of the input
    int size = strtol(argv[2], NULL, 0);
    // Open file
    int fd = open(argv[1], O_RDWR|O_CREAT, 0644);
    abort_on_error(fd == -1, "Error opening or creating file");

    // Use lseek() and write() to create the file of the needed size
    abort_on_error(lseek(fd, size, SEEK_SET) == -1, "Error in lseek");
    write_int(fd, size); // To truly extend the file 

    //Close file
    abort_on_error(close(fd) == -1, "Error closing file");
    return EXIT_SUCCESS;
}
4

2 回答 2

6

根据其实现,您的程序完全符合我的预期:

  • 假设命名文件最初不存在,它会创建它
  • int它将值为 5 的( )的 4 个字节写入sizeof(int)文件,从偏移量 5 开始
  • 它在偏移量 0 - 4 处不写入任何内容;这些用空字节填充。

结果是一个九字节的文件,带有字节值(不可打印的数字):

0 0 0 0 0 5 0 0 0

(我的系统是 little-endian。)请特别注意,该文件在任何意义上都不是文本文件。如果您期望一个文本文件,看起来确实如此,您可能确实会看到与它有关的意外行为,您可能将其描述为无法访问它。

那么一些考虑:

  • 文件的第五个字节在偏移量 4 处,而不是 5。
  • 如果您想写数字“5”,请将其存储在 a 中char并写下char; 不要写它的int表示。或者,将文件描述符包装在流中并使用流 I/O 函数,例如fputc().
  • 如果您想用空字节以外的任何内容填充其他空间,那么您需要手动执行此操作。
  • 据我所知,这完全符合 POSIX 的要求。特别是,它说的是 lseek:

lseek() 函数应允许将文件偏移量设置为超出文件中现有数据的末尾。如果稍后在此点写入数据,则后续读取间隙中的数据应返回值为 0 的字节,直到数据实际写入间隙。

( POSIX 1003.1-2008, 2016 版)

于 2017-01-05T17:35:32.703 回答
-2

在某些(非常旧的?)系统lseek上,不允许您搜索文件末尾,如果您尝试它,您会收到EINVAL错误消息。

相反,您想先使用ftruncate更改文件大小,然后使用lseek寻找您要读取(或写入)的文件中的位置。对于您的示例:

ftruncate(fd, 5);         // set file size to 5
lseek(fd, SEEK_END, 0);   // reposition to new end
write(fd, &v, sizeof(v);  // write data (extending the file)
于 2017-01-05T17:31:17.533 回答