#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
fp = fopen("clients.dat", "wb");
fclose(fp);
fp = fopen("clients.dat", "rb");
while (1) {
if (fp == EOF)
break;
else
printf("There is something inside a file");
}
fclose(fp);
return 0;
}
Here comes a question: what do empty binary files contain? should the pointer point to the EOF character? I mean: isn't it that the first and last thing in the file is EOF? OR how Can I check whether a file is empty or not?
An empty file contains nothing, it is empty. So it contains 0 bytes. EOF is not a character that is at the end of a file, it is an integer constant used as return value from some of the standard methods reading from a file to indicate end of file or some sort of error.
When you open a file you get a pointer to a FILE type back, this is what you can expect even from an empty file.
A file is not terminated the same way a string is, so there is no equivalent of a NULL character in a file, that determines when the file contents stops.
To determine whether a file you have opened and have a valid FILE pointer to is empty you can use fseek and ftell:
fseek(fp, 0, SEEK_END);
size = ftell(fp);
if (size == 0) {
// File is empty
}
Function fopen returns a pointer to a file handle of type FILE, not a pointer to any content of the file or a pointer to an EOF-character. The pointer is NULL if the file could not be opened at all, but does not indicate whether the file is empty or not.
To check if a file is empty you either (1) need to make an attempt to read bytes and handle the various results, or (2) to use fseek and ftell to move the read pointer to the end and ask then for the position.
(1)
fp=fopen("clients.dat","rb");
char buffer;
size_t bytesRead = fread(&buffer, 1, 1, fp); // try to read one byte
if(bytesRead == 1) {
printf("file contains at least one byte\n");
} else { // error handling
if (feof(fp))
printf("Attemt to read though end of file has been reached. File is empty.\n");
else if (ferror(fp)) {
perror("Error reading file.");
}
}
(2)
fp=fopen("clients.dat","rb");
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
if (size==0) {
// file is empty.
}
I'd prefer the second variant.
Here's another approach:
To check if the file is empty, you can simply read the file:
int c = fgetc(fp);
if (c == EOF)
{
// The file is empty or an error occured
if (feof(fp))
{
// Empty
}
else
{
// Error during file read
}
}
else
{
// non-empty file
}
Here comes a question what empty binary files contain ?
Empty files contain nothing, that is what makes them empty.
Regular files have a size which is not part of their data, but instead is normally a part of the directory entry or inode.
should the pointer point to the EOF character ?
No
First of all the pointer returned by fopen is NOT a pointer to the content of the file, but merely a pointer to a data structure describing the open file.
Secondly EOF is not an actual part of the file, but a special return value from the getc family of functions used to indicate that the end of file has been reached.
To test whether you are at the end of a file without reading from it you can use the feof function.
Related
I am implementing the program to zip a file using a run-length encoding compression method. Are there any ways you can compare the characters in the file or compare two file pointers to do that?
I opened the file(zipfilename) that I want to zip and set the file pointer named ftozip to it. Then, I tried to count the number of each character using this file pointer as shown in the code below (if condition).
FILE *ftozip;
ftozip = fopen(argv[1],"r");//open the file that we are zipping
if (ftozip == NULL) {//if there is an error opening
perror("File cannot be opened ");
}
char zipfilename[30];
strcat(zipfilename, argv[1]);
strcat(zipfilename,".zip");
FILE *zipfilep = fopen(zipfilename, "a"); //zipfile openned to write
int count = 1;
while(1){ //incrementing the characters and storing in the zip file
if(*ftozip == *(ftozip +1)) {
count++;
char countchar[] = (char)count+(*ftozip);
fputs(countchar, zipfilep);
ftozip++;
continue;
}
else {
count = 1;
countchar = (char)count + (*ftozip);
ftozip++;
if (feop(ftozip){
break;
}
continue;
}
}
That resulting in this error "invalid operands to binary == (have ‘FILE’ and ‘FILE’)".
Dereferencing a pointer of type FILE*, as you do with if(*ftozip == *(ftozip +1) ..., does not access the contents of the file.
To read or write from or to a file bytewise, use fread and fwrite instead.
I created a function that is successfully reading the binary file but it is not printing as I wanted.
The function:
void print_register() {
FILE *fp;
fp = fopen("data.bin", "rb");
if (fp == NULL) {
error_message("Fail to open data.bin for reading");
exit(0);
}
reg buffer;
while (EOF != feof(fp)) {
fread(&buffer, sizeof(reg), 1, fp);
printf("%s %d %d\n", buffer.name, buffer.age, buffer.id);
}
fclose(fp);
}
Note: reg is a typedef for a struct:
typedef struct registers reg;
struct registers {
char name[30];
int age;
int id;
char end;
};
Function for writing the file:
void register_new() {
system("clear");
reg buffer;
FILE *fp;
fp = fopen("data.bin", "ab");
if (fp == NULL) {
error_message("Error opening file data.bin");
exit(0);
}
write_register(buffer);
fwrite(&buffer, sizeof(reg), 1, fp);
fclose(fp);
}
Posting a printscreen of what was print to be more helpful:
As you can see on image, after the "p" (command for printing) is where should be the name, age and id of the struct.
In register_new(), you have to send the address of buffer in order for write_register() to work properly (right now you're giving it a copy of buffer).
Replace:
write_register(buffer);
with:
write_register(&buffer);
Then correct write_register to take and work with an address instead of a structure.
This might help you understand what's going on: http://fresh2refresh.com/c-programming/c-passing-struct-to-function
Your reading loop is incorrect. Don't use feof(), it can only tell is you have reached the end of file after a read attempt failed and it might not return EOF anyway, it is only specified as returning 0 or non 0. Use this instead:
while (fread(&buffer, sizeof(reg), 1, fp) == 1) {
printf("%s %d %d\n", buffer.name, buffer.age, buffer.id);
}
fread returns the number of items successfully read. Here you request to read 1 item of size sizeof(reg), if the item was read successfully, fread will return 1, otherwise it will return 0 (in case of a read error or end of file reached).
Your screenshot shows a syntax error, which you seem to have fixed now. Remove that, it is not helping.
In your function register_new, you are writing an uninitialized structure reg to the file, no wonder it does not contain anything useful when you read it back from the file. And for what it is worth, opening this file in binary mode is the correct thing to do since it contains binary data, namely the int members of the structure.
The reg passed to fwrite is indeed uninitialized. write_register gets a copy of this uninitialized structure by value, and probably modifies this copy, but this does not affect the local structure in register_new. You should modify write_register() to take a pointer to the structure. Unlike C++, there is no passing by reference in C.
I'm working on a project, and I can't seem to figure out why a piece of my function for finding prime numbers won't run. Essentially, I want to code to first check the text file log for any previously encountered prime numbers, but no matter what I put for the while-loop containing fscanf(), it seems like my code never enters it.
int filePrime(int a) {
int hold = 0;
FILE *fp = fopen("primes.txt", "a+");
if (fp == NULL) {
printf("Error while opening file.");
exit(2);
}
/*
the while loop below this block is the one with the issue.
on first run, it should skip this loop entirely, and proceed
to finding prime numbers the old-fashioned way, while populating the file.
instead, it is skipping this loop and proceeding right into generating a
new set of prime numbers and writing them to the file, even if the previous
numbers are already in the file
*/
while (fscanf(fp, "%d", &hold) == 1){
printf("Inside scan loop.");
if (hold >= a) {
fclose(fp);
return 1;
}
if (a % hold == 0) {
fclose(fp);
return 0;
}
}
printf("Between scan and print.\n");
for (; hold <= a; hold++) {
if (isPrime(hold) == 1) {
printf("Printing %d to file\n", hold);
fprintf(fp, "%d\n", hold);
if (hold == a)
return 1;
}
}
fclose(fp);
return 0;
}
I have tried all sorts of changes to the while-loop test.
Ex. != 0, != EOF, cutting off the == 1 entirely.
I just can't seem to get my code to enter the loop using fscanf.
Any help is very much appreciated, thank you so much for your time.
In a comment, I asked where the "a+" mode leaves the current position?
On Mac OS X 10.11.4, using "a+" mode opens the file and positions the read/write position at the end of file.
Demo code (aplus.c):
#include <stdio.h>
int main(void)
{
const char source[] = "aplus.c";
FILE *fp = fopen(source, "a+");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s\n", source);
}
else
{
int n;
char buffer[128];
fseek(fp, 0L, SEEK_SET);
while ((n = fscanf(fp, "%127s", buffer)) == 1)
printf("[%s]\n", buffer);
printf("n = %d\n", n);
fclose(fp);
}
return(0);
}
Without the fseek(), the return value from n is -1 (EOF) immediately.
With the fseek(), the data (source code) can be read.
One thing slightly puzzles me: I can't find information in the POSIX fopen() specification (or in the C standard) which mentions the read/write position after opening a file with "a+" mode. It's clear that write operations will always be at the end, regardless of intervening uses of fseek().
POSIX stipulates that the call to open() shall use O_RDWR|O_CREAT|O_APPEND for "a+", and open() specifies:
The file offset used to mark the current position within the file shall be set to the beginning of the file.
However, as chux notes (thanks!), the C standard explicitly says:
Annex J Portability issues
J.3 Implementation-defined behaviour
J.3.12 Library functions
…
Whether the file position indicator of an append-mode stream is initially positioned at
the beginning or end of the file (7.21.3).
…
So the behaviour seen is permissible in the C standard.
The manual page on Mac OS X for fopen() says:
"a+" — Open for reading and writing. The file is created if it does not exist. The stream is positioned at the end of the file. Subsequent writes to the file will always end up at the then current end of file, irrespective of any intervening fseek(3) or similar.
This is allowed by Standard C; it isn't clear it is fully POSIX-compliant.
I want to transfer a file via a socket in linux system. I know how to use fgetc() and EOF to do so, or first get the length of file. Is there any other option?
Check for the return value of fread(). If the return value is not equal to the 3rd parameter passed into fread(), either error happens or EOF is reached.
Function fread() reads data from the given data stream(4th parameter) to an array pointed in to by a pointer(1st parameter)
fread (pointer to the block of memory, size of an element, number of elements, pointer to the input file)
fread() reads from where it left off last time and returns the number of elements successfully read. So if u do as below fread() will not go beyond that.
*You have to edit the number of elements according to the input file.
// Open input file
FILE *inptr = fopen (infile, "r");
//Check for a valid file
if (inptr == NULL)
{
fprintf (stderr, "Could notopen %s", infile);
return 1;
}
// Memory allocation for buffer
int *buffer = malloc(512);
// Read input file
while (fread (&buffer, 1, 512, inptr) == 512)
{
// DO WHAT YOU NEED HERE
}
// Free memory from buffer
free(buffer);
// close infile
fclose(inptr);
return 0;
I am reaing from a file, and when i read, it takes it line by line, and prints it
what i want exactly is i want an array of char holding all the chars in the file and print it once,
this is the code i have
if(strcmp(str[0],"#")==0)
{
FILE *filecomand;
//char fname[40];
char line[100];
int lcount;
///* Read in the filename */
//printf("Enter the name of a ascii file: ");
//fgets(History.txt, sizeof(fname), stdin);
/* Open the file. If NULL is returned there was an error */
if((filecomand = fopen(str[1], "r")) == NULL)
{
printf("Error Opening File.\n");
//exit(1);
}
lcount=0;
int i=0;
while( fgets(line, sizeof(line), filecomand) != NULL ) {
/* Get each line from the infile */
//lcount++;
/* print the line number and data */
//printf("%s", line);
}
fclose(filecomand); /* Close the file */
You need to determine the size of the file. Once you have that, you can allocate an array large enough and read it in a single go.
There are two ways to determine the size of the file.
Using fstat:
struct stat stbuffer;
if (fstat(fileno(filecommand), &stbuffer) != -1)
{
// file size is in stbuffer.st_size;
}
With fseek and ftell:
if (fseek(fp, 0, SEEK_END) == 0)
{
long size = ftell(fp)
if (size != -1)
{
// succesfully got size
}
// Go back to start of file
fseek(fp, 0, SEEK_SET);
}
Another solution would be to map the entire file to the memory and then treat it as a char array.
Under windows MapViewOfFile, and under unix mmap.
Once you mapped the file (plenty of examples), you get a pointer to the file's beginning in the memory. Cast it to char[].
Since you can't assume how big the file is, you need to determine the size and then dynamically allocate a buffer.
I won't post the code, but here's the general scheme. Use fseek() to navigate to the end of file, ftell() to get size of the file, and fseek() again to move the start of the file. Allocate a char buffer with malloc() using the size you found. The use fread() to read the file into the buffer. When you are done with the buffer, free() it.
Use a different open. i.e.
fd = open(str[1], O_RDONLY|O_BINARY) /* O_BINARY for MS */
The read statement would be for a buffer of bytes.
count = read(fd,buf, bytecount)
This will do a binary open and read on the file.