如何正确使用lseek()来扩展文件大小?

时间:2017-01-05 17:09:42

标签: c file lseek

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

运行例如:

$ ./lseek_test myFile 5

我希望它能创建一个名为myFile的5个字节的文件,其最后一个字节被数字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;
}

2 个答案:

答案 0 :(得分:6)

根据其实施情况,您的计划完全符合我的预期:

  • 假设指定的文件最初不存在,则创建它
  • 它将值为5的intsizeof(int))的4个字节写入文件,从偏移量5开始
  • 它在偏移0 - 4处没有写入任何内容;这些都填充了空字节。

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

0 0 0 0 0 5 0 0 0

(我的系统是little-endian。)特别注意,该文件在任何意义上都不是 text 文件。如果您期望一个文本文件,就像在这种情况下一样,您可能确实会看到关于它的意外行为,您可能会将其描述为无法访问它。

然后考虑一些事项:

  • 文件的第五个字节从头开始偏移4,而不是5。
  • 如果你想写数字&#39; 5&#39;然后将其存储在char中并写下char;不要写它的int表示。或者,将文件描述符包装在流中并使用流I / O函数,例如fputc()
  • 如果你想用空字节以外的任何东西填充其他空格,那么你需要手动完成。
  • 据我所知,这完全符合POSIX的要求。特别是,它说的是lseek:
  

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

POSIX 1003.1-2008, 2016 Edition

答案 1 :(得分:-2)

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

相反,您希望先使用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)