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
$
Related
I want to make copy/paste with using c FILE but i need to add read/write buffer too and I am not sure how to add it. Is there any function similar to regular read/write..Code is below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
FILE* fsource, * fdestination;
printf("enter the name of source file:\n");
char sourceName[20], destinationName[20];
strcpy(sourceName, argv[1]);
strcpy(destinationName, argv[2]);
fsource = fopen(sourceName, "r");
if (fsource == NULL)
printf("read file did not open\n");
else
printf("read file opened sucessfully!\n");
fdestination = fopen(destinationName, "w");
if (fdestination == NULL)
printf("write file did not open\n");
else
printf("write file opened sucessfully!\n");
char pen = fgets(fsource);
while (pen != EOF)
{
fputc(pen, fdestination);
pen = fgets(fsource);
}
fclose(fsource);
fclose(fdestination);
return 0;
}
Here's a reworking of your code (sans some error handling) that reads and writes in 256-byte increments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *sourceName = argv[0];
char destName[256];
snprintf(destName, 256, "%s.copy", sourceName);
printf("Copying %s -> %s\n", sourceName, destName);
FILE *fsource = fopen(sourceName, "rb");
FILE *fdest = fopen(destName, "w");
char buffer[256];
for (;;) {
size_t bytesRead = fread(buffer, 1, 256, fsource);
if (bytesRead == 0) {
break;
}
if (fwrite(buffer, 1, bytesRead, fdest) != bytesRead) {
printf("Failed to write all bytes!");
break;
}
printf("Wrote %ld bytes, position now %ld\n", bytesRead, ftell(fdest));
}
fclose(fsource);
fclose(fdest);
return 0;
}
The output is e.g.
$ ./so64481514
Copying ./so64481514 -> ./so64481514.copy
Wrote 256 bytes, position now 256
Wrote 256 bytes, position now 512
Wrote 256 bytes, position now 768
Wrote 256 bytes, position now 1024
[...]
Wrote 168 bytes, position now 12968
This program is meant to take as parameter a file, then read a string from standard input and write its length into the file, then read the content of the file (which is supposed to contain the lengths of the strings from the standard input) and write it in standard output:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX_BUFF 4096
int main(int argc, char **argv)
{
if (argc != 2)
{
puts("you must specify a file!");
return -1;
}
int nRead;
char buffer[MAX_BUFF], tmp;
int fd;
puts("write \"end\" to stop:");
fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRWXU);
while ((nRead = read(STDIN_FILENO, buffer, MAX_BUFF)) > 0 && strncmp(buffer,"end", nRead-1) != 0 )
{
if ( write(fd, &nRead, 1) < 0 )
{
perror("write error.");
return -1;
}
}
puts("now i am gonna print the length of the strings:");
lseek(fd, 0, SEEK_SET); //set the offset at start of the file
while ((nRead = read(fd, buffer, 1)) > 0)
{
tmp = (char)buffer[0];
write(STDOUT_FILENO, &tmp, 1);
}
close(fd);
return 0;
}
this is the result:
write "end" to stop:
hello
world
i am a script
end
now i am gonna print the length of the strings:
I tried to convert the values written in the file into char before write in standard output with no success.
How am i supposed to print on standard output the lengths by using unbuffered I/O? Thank you for your replies
EDIT: i changed the read from file with this:
while((read(fd, &buffer, 1)) > 0)
{
tmp = (int)*buffer;
sprintf(buffer,"%d:", tmp);
read(fd, &buffer[strlen(buffer)], tmp);
write(STDOUT_FILENO, buffer, strlen(buffer));
}
but actually i have no control on the effective strlen of the string thus the output is this:
13:ciao atottti
4:wow
o atottti
5:fine
atottti
as you can see, the strlength is correct because it consinder the newline character ttoo. Still there is no control on the effective buffer size.
I'm not good at C and I'm trying to do something simple. I want to open a binary file, read blocks of 1024 bytes of data and dump into a buffer, process the buffer, read another 1024 byes of data and keep doing this until EOF. I know how / what I want to do with the buffer, but it's the loop part and file I/O I keep getting stuck on.
PSEUDO code:
FILE *file;
unsigned char * buffer[1024];
fopen(myfile, "rb");
while (!EOF)
{
fread(buffer, 1024);
//do my processing with buffer;
//read next 1024 bytes in file, etc.... until end
}
fread() returns the number of bytes read. You can loop until that's 0.
FILE *file = NULL;
unsigned char buffer[1024]; // array of bytes, not pointers-to-bytes
size_t bytesRead = 0;
file = fopen(myfile, "rb");
if (file != NULL)
{
// read up to sizeof(buffer) bytes
while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0)
{
// process bytesRead worth of data in buffer
}
}
#include <stdio.h>
#include <unistd.h> // For system calls write, read e close
#include <fcntl.h>
#define BUFFER_SIZE 1024
int main(int argc, char* argv[]) {
unsigned char buffer[BUFFER_SIZE] = {0};
ssize_t byte = 0;
int fd = open("example.txt", O_RDONLY);
while ((byte = read(fd, buffer, sizeof(buffer))) != 0) {
printf("%s", buffer);
memset(buffer, 0, BUFFER_SIZE);
}
close(fd);
return 0;
}
Edited code added
#include <stdio.h>
#include <unistd.h> // For system calls write, read e close
#include <fcntl.h>
#define BUFFER_SIZE 1024
int main(int argc, char* argv[]) {
unsigned char buffer[BUFFER_SIZE] = {0};
ssize_t byte = 0;
// open file in read mode
int fd = open("example.txt", O_RDONLY);
// file opening failure
if (fd == -1) {
printf("Failed to open file\n");
return -1;
}
// loop
while (1) {
// read buffer
byte = read(fd, buffer, sizeof(buffer));
// error
if (byte == -1) {
printf("Encountered an error\n");
break;
} else if (byte == 0) {
// file end exit loop
printf("File reading end\n");
break;
}
// printf file data
printf("%s", buffer);
memset(buffer, 0, BUFFER_SIZE);
}
// Close file
close(fd);
return 0;
}
Below is my simple cat problem, which reads a file and print it on terminal. When I set the BUFISZE macro to 10, it works fine. If I set BUFSIZE to 100, it prints part of the file. If I set BUFIZE to 1024, it prints nothing. Could you anyone please explain what is going on?
#include <stdio.h>
#include <string.h>
#define BUFSIZE 10
int main(int argc, char **argv){
char buf[BUFSIZE];
FILE *fp;
if( (fp = fopen(*++argv, "r")) == NULL){
printf("cannot open %s\n", *argv);
return 1;
}
while( fread(buf, BUFSIZE, 1, fp) == 1 )
if (fwrite(buf,strlen(buf), 1, stdout) != 1 ){
printf("write error.\n");
return 2;
}
printf("\n");
return 0;
}
Don't use strlen here; you are not dealing with null-terminated strings here. You read fixed blocksizes. You should write the same amount of chars that you have read.
fread returns the number of elements of the given size that were successfully read. Use this information in your call to fread. For this to work, you must treat the data as BUFSIZE bytes, not as one block of BUFSIZE bytes. (If that sounds esoteric: Swap your second and third parameters in fread and fwrite. These functions cannot return a number greater than their third parameter, the element count.)
So:
char buf[BUFSIZE];
size_t n;
do {
n = fread(buf, 1, BUFSIZE, stdin);
if (n > 0) fwrite(buf, 1, n, stdout);
} while (n == BUFSIZE);
code:
#include <fcntl.h>
#include <linux/fs.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
void write_zero(char * file, unsigned long bytes)
{
printf("Zeroing %s\n", file);
unsigned int wrote = 0, total = 0;
int fd, i, buf;
char obj = 0x00;
fd = open(file, O_RDWR, DEFFILEMODE);
lseek(fd, 0, SEEK_SET);
write(fd, &obj, bytes);
}
int main(int argc, char * * argv)
{
int fd;
unsigned long blocks = 0;
char check = 0x0;
fd = open(argv[1], O_RDONLY);
ioctl(fd, BLKGETSIZE, &blocks);
close(fd);
printf("Blocks: %lu\tBytes: %lu\tGB: %.2f\n",
blocks, blocks * 512, (double)blocks * 512.0 / (1024 * 1024 * 1024));
do
{
printf("Write 0x0 to %s? [y/N] ", argv[1]);
fflush(stdout);
}
while (scanf("%c", &check) < 1);
if (check == 'y')
{
write_zero(argv[1], blocks * 512);
}
}
I get nothing actually written to the device.. I copied my open line from the 'dd' source code, thinking maybe it was not opened right. dd can zero the device, but this program does not. Any ideas?
It seems like this has been beaten to death but
char obj = 0x00;
fd = open(file, O_RDWR, DEFFILEMODE);
lseek(fd, 0, SEEK_SET);
write(fd, &obj, bytes);
Is not going to write zeros. It's going to write garbage from the stack.