【问题标题】:lseek() Trying to use with a byte file but pointer is of FILE typelseek() 尝试使用字节文件,但指针是 FILE 类型
【发布时间】:2018-03-14 03:40:19
【问题描述】:

这是一个让每个人都知道的项目。这是我在 C 语言中的第一个项目,对lseek() 和移动文件指针有疑问。

现在我可以读取位图文件的位图和 DIB 标头。我现在需要遍历像素并以某些方式操作它们。我已经用伪代码写出了我打算如何处理这种操作。但是我很难理解如何正确使用lseek,因为我的代码不断收到incompatible pointer to integer conversion... 警告。我将给出我的主要方法的一个简短示例,因为这是一个项目:

int main(int argc, const char * argv[]) {

    FILE *fp;

    if((fp = fopen(argv[1], "r+b")) == NULL){
        printf("Error:  Unable to open file.\n");
        exit(0);
    }

    fseek(fp, 0, SEEK_END);
    long fsize = ftell(fp);
    rewind(fp);

    char test;  // simply to test overwriting the current byte

    fread(&test, sizeof(char), 1, fp);
    test = ~test;
    lseek(fp, -1, SEEK_CUR); //produces error
    //also tried fseek prior to realizing I should be using lseek to move my pointer.
    fwrite(&test, 1, sizeof(char), fp);

    fclose(fp);
    return 0;
}

同样,由于这是一个项目,所以不要试图提供太多我的代码。但我想帮助了解如何正确使用lseek。我注意到它返回一个int 值,所以我知道这是因为我的文件指针是FILE 类型。但是使用这种方法的正确方法是什么?我看到了一个例子,它以读写模式打开了同一个文件,其中写入模式使用lseek。但由于某种原因,我不知道这是否正确。

已编辑 根据两位成员的回复,我将上面的代码更改为:

rewind(fp);
lseek(fileno(fp), hdr.offset, SEEK_CUR); //hdr.offset == 54 bytes
printf("FD FILENO:  %d\n", fileno(fp)); // prints 3???
printf("CURRENT POS: %p\n", fp);  //prints 0x7fffe7eae0b0 (I understand it's an address)
fread(&test, sizeof(char), 1, fp);
lseek(fileno(fp), -1, SEEK_CUR);
fwrite(&test, 1, sizeof(char), fp);
printf("CURRENT POS: %p\n", fp);  //prints the same address as above?

除了与 C 相关的一切,我没有得到什么?

【问题讨论】:

  • 第 6 行:fileno(fp) 而不是 file(fp)
  • 为什么要使用lseek() 而不是fseek()
  • @duskwuff 是的,因为我需要能够在读写字节时在字节之间来回移动指针。
  • 提示:“我很难理解如何正确使用 lseek” --> 那么为什么代码不检查 fseek, rewind, fread,lseek, ... 的返回值以确保代码正常运行?代码很好地做到了fopen。通过测试返回值可以获得很多洞察力和代码信心。
  • 不要将lseekstdio 例程混用。 FILE * 具有内部缓冲,并且不会知道您确实干预了 lseeks。使用fseek

标签: c pointers bitmap file-handling lseek


【解决方案1】:

如果您想继续使用FILE *fp,这可能是个好主意,您可以使用int fileno(FILE *stream)fp 转换为其对应的int 文件描述符。换句话说,

lseek(fileno(fp), -1, SEEK_CUR); 

已添加

fseek 一切正常。

#include <stdio.h>

int main(int argc, const char *argv[]) {
  if (argc < 2) {
    fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
    return 1;
  }
  FILE *fp;
  if((fp = fopen(argv[1], "r+b")) == NULL){
    fprintf(stderr, "Error:  Unable to open fle '%s'.\n", argv[1]);
    return 1;
  }
  char buf[17];
  size_t n_read = fread(buf, sizeof(char), sizeof buf - 1, fp);
  buf[n_read] = '\0';
  printf("Initial contents: %s\n", buf);

  fseek(fp, 0, SEEK_END);
  long fsize = ftell(fp);
  printf("Position at end of file: %ld\n", fsize);

  // Read first character in file.
  rewind(fp);
  char test;
  fread(&test, sizeof(char), 1, fp);

  ++test;
  fseek(fp, -1, SEEK_CUR);
  fwrite(&test, sizeof(char), 1, fp);

  rewind(fp);
  n_read = fread(buf, sizeof(char), sizeof buf - 1, fp);
  buf[n_read] = '\0';
  printf("Final contents: %s\n", buf);

  fclose(fp);
  return 0;
}

然后

$ gcc foo.c -o foo
$ ./foo foo.c
Initial contents: #include <stdio.
Position at end of file: 881
Final contents: $include <stdio.

【讨论】:

  • 我已经结合了你和@YaatSuka 的建议,但仍然没有得到我想得到的输出。请查看我的编辑并感谢您的建议!
  • @Pwrcdr87 你得到了预期的结果。文件句柄是在大多数 C 实现中以 3 开头的小整数,因为 0、1、2 用于 stdinstdoutstderr。如果您打开一个不同的文件,它可能会得到4 等。fp 是指向内存中FILE 数据结构的指针。它不会改变。你在期待什么?也许您打算ftell() 查看当前流位置。这就是通过调用任何seek 变体来调整的。但是 C 标准不保证 ftell 结果是字节偏移;只有fseek 将文件置于相同状态。
  • 顺便说一句,你对fseek()有什么意见?
  • 我个人并不反对fseek(),但我认为我的问题是我没有完全理解它的用途以及如何正确检索它的当前值。我记得我的教授提到了lseek(),但不记得他说过它是否可用。
【解决方案2】:

这里fpFILE * 的类型,但lseek 将int 作为第一个参数。
所以用 open 代替 fopen:

int main(int argc, const char * argv[]) {

int fp;

// Open return the file descriptor
if((fp = open(argv[1], O_RDWR | O_WRONLY)) == -1){
    printf("Error:  Unable to open file.\n");
    exit(0);
}

// Rest of the function

lseek(fp, -1, SEEK_CUR);    

[编辑]

另一个问题是使用fileno() 函数。
fileno()FILE * 作为参数并返回lseek() 函数所需的file_descriptor (int)。
你可以这样使用它:

int main(int argc, const char * argv[]) {

FILE *fp;
int  fd;

// Open return the file descriptor
if((fp = fopen(argv[1], "r+b")) == NULL){
    printf("Error:  Unable to open file.\n");
    exit(0);
}
if ((fd = fileno(fp)) == -1){
    printf("Fileno Error\n");
    exit(0);
}

// Rest of the function

lseek(fd, -1, SEEK_CUR);

这是文档 => https://linux.die.net/man/3/fileno

【讨论】:

  • 所以我需要在我的文件中维护 (2) 个指针?现在我正在使用fread 将值填充到带有标题信息的structs 中。为这个可能很愚蠢的问题道歉,但你是说当我使用fopen 作为我当前的FILE *fp 时,我还应该用另一个int 指针和open 跟进它吗?我也必须查找这些论点,因为它们对我来说是新的。
  • 谢谢!在你发布之后,我当然找到了stackoverflow.com/questions/3167298/…。我没有正确表达我的问题,让我感到困惑。我试试看!
  • 我已经添加了您提到的代码,但没有看到我期望的响应。请看我上面的编辑,不要害怕以非常严厉和批评的方式告诉我我做错了什么。
猜你喜欢
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多