Вопрос

While programming with files I stumbled upon some strange difference between the C library 'fread' function and the POSIX call 'read'; 'read' only reads a few bytes of a file while 'fread' reads the whole file. This code only reads 1024 + 331 bytes, and then 'read' returns 0:

char buf[1024];
int id = open("file.ext", 0);
int len;
while((len = read(id, buf, 1024)) > 0)
    println(len);

while this code reads the whole file as expected, around 11kb:

char buf[1024];
FILE* fp = fopen("file.ext", "rb");
int len;
while((len = fread(buf, 1, 1024, fp)) > 0)
    println(len);

Can you tell why 'read' doesn't read the whole file?

EDIT2: I am sorry, I am using windows with MinGW, and reading a binary file

EDIT: A complete example:

#include <io.h>
#include <stdio.h>

int main() {

    char buf[1024];
    int len;

    // loop 1
    int id = open("file.ext", 0);
    while((len = read(id, buf, 1024)) > 0) {
        printf("%d\n", len);
    }
    close(id);

    println("--------");

    // loop 2
    FILE* fp = fopen("file.ext", "rb");
    while((len = fread(buf, 1, 1024, fp)) > 0) {
        printf("%d\n", len);
    }
    fclose(fp);

    while(1) {}

    return 0;
}

The output:

1024
331
--------
1024
1024
1024
1024
1024
1024
1024
1024
1024
1024
981
Это было полезно?

Решение

You're opening the file the first time in text mode and the second time in binary mode. You need to open it both times in binary mode. If it's not in binary mode, the first control-z (hex value 1A) signals the "end of file".

Add the following includes (getting rid of <io.h>):

#include <unistd.h>
#include <fcntl.h>

The call open like this:

int id = open("spiderman.torrent", O_RDONLY|O_BINARY);

Here's an example of control-z ending the file:

#include <stdio.h>

void writeit() {
  FILE *f = fopen("test.txt", "wb");
  fprintf(f, "hello world\r\n");
  fputc(0x1A, f);
  fprintf(f, "goodbye universe\r\n");
  fclose(f);
}

void readit() {
  int c;
  FILE *f = fopen("test.txt", "r");
  while ((c = fgetc(f)) != EOF)
    putchar(c);
  fclose(f);
}

int main() {
  writeit();
  readit();
  return 0;
}

The above only prints "hello world" and not "goodbye universe".

Другие советы

The question was updated...

The fread() loop is weird:

while ((len = fread(buf, 1, 1024, fp) > 0))
    println(len);

Look at the parentheses — they're equivalent to:

while ((len =   (fread(buf, 1, 1024, fp) > 0)   ))

Now, fread() will return the number of bytes read, but the value assigned to len will be 0 or 1, so the printing from println() should repeat 1 a few times and then stop.

Is that you're actual code, or did you make a typing error in creating the question?

Compile and run this program (I called it rd compiled from rd.c):

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#define FILENAME "file.ext"

static void println(int val)
{
    printf("%d\n", val);
}

int main(void)
{
    char buf[1024];
    int len;

    int id = open(FILENAME, 0);
    while ((len = read(id, buf, 1024)) > 0)
        println(len);
    close(id);

    FILE *fp = fopen(FILENAME, "rb");
    while ((len = fread(buf, 1, 1024, fp)) > 0)
        println(len);
    fclose(fp);

    struct stat sb;
    stat(FILENAME, &sb);
    printf("Size: %d\n", (int)sb.st_size);
    return 0;
}

Example output:

$ ls -l file.ext
-rw-r--r--  1 jleffler  staff  7305 Apr  6 08:08 file.ext
$ ./rd
1024
1024
1024
1024
1024
1024
1024
137
1024
1024
1024
1024
1024
1024
1024
137
Size: 7305
$
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top