How do i check if a file is empty in C? - c

I'm importing a txtfile into my file, how do i check if the input file is blank.
I already check if it cannot read the input. This is what i have so far:
#include<stdio.h>
#include<stdlib.h>
int main (int argc, char *argv[]){
// argv[1] will contain the file name input.
FILE *file = fopen(argv[1], "r");
// need to make sure the file is not empty, error case.
if (file == NULL){
printf("error");
exit(0);
}
// if the file is empty, print an empty line.
int size = ftell(file); // see if file is empty (size 0)
if (size == 0){
printf("\n");
}
printf("%d",size);
the size checking obviously does not work because i put in a few numbers and the size is still 0. any suggestions?

If you are working with a regular file (e.g., a text file), you can use sys/stat.h and call the value of the st_size struct member:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main (int argc, char *argv[]) {
if (argc != 2) {
return EXIT_FAILURE;
}
const char *filename = argv[1];
struct stat st;
if (stat(filename, &st) != 0) {
return EXIT_FAILURE;
}
fprintf(stdout, "file size: %zd\n", st.st_size);
return EXIT_SUCCESS;
}

how about try read first row.
and see what characters you get?

Call ftell() does not tell you the size of the file. From the man page:
The ftell() function obtains the current value
of the file position indicator for the stream
pointed to by stream.
That is, it tell you your current position in the file...which will always be 0 for a newly opened file. You need to seek to the end of the file first (see fseek()).

ftell will tell you the position the file pointer is at, and immediately after you opened the file, this position is always 0.
You either use stat before opening, or use fseek to seek some distance in the file (or at end) and then use ftell.
Or you delay the check until afterwards. I.e., you try to read whatever you need to read, and then verify whether you succeeded or not.
Update: and speaking of checks, you have no guarantee that
// argv[1] will contain the file name input.
For that, you need to check out that argc is at least 2 (the first argument being the executable name). Otherwise your file name might be NULL. fopen should simply return NULL, but in other scenarios you might find yourself looking at a core dump.

Related

fgets statement reads first line and not sure how to modify because I have to return a pointer [duplicate]

I need to copy the contents of a text file to a dynamically-allocated character array.
My problem is getting the size of the contents of the file; Google reveals that I need to use fseek and ftell, but for that the file apparently needs to be opened in binary mode, and that gives only garbage.
EDIT: I tried opening in text mode, but I get weird numbers. Here's the code (I've omitted simple error checking for clarity):
long f_size;
char* code;
size_t code_s, result;
FILE* fp = fopen(argv[0], "r");
fseek(fp, 0, SEEK_END);
f_size = ftell(fp); /* This returns 29696, but file is 85 bytes */
fseek(fp, 0, SEEK_SET);
code_s = sizeof(char) * f_size;
code = malloc(code_s);
result = fread(code, 1, f_size, fp); /* This returns 1045, it should be the same as f_size */
The root of the problem is here:
FILE* fp = fopen(argv[0], "r");
argv[0] is your executable program, NOT the parameter. It certainly won't be a text file. Try argv[1], and see what happens then.
You cannot determine the size of a file in characters without reading the data, unless you're using a fixed-width encoding.
For example, a file in UTF-8 which is 8 bytes long could be anything from 2 to 8 characters in length.
That's not a limitation of the file APIs, it's a natural limitation of there not being a direct mapping from "size of binary data" to "number of characters."
If you have a fixed-width encoding then you can just divide the size of the file in bytes by the number of bytes per character. ASCII is the most obvious example of this, but if your file is encoded in UTF-16 and you happen to be on a system which treats UTF-16 code points as the "native" internal character type (which includes Java, .NET and Windows) then you can predict the number of "characters" to allocate as if UTF-16 were fixed width. (UTF-16 is variable width due to Unicode characters above U+FFFF being encoded in multiple code points, but a lot of the time developers ignore this.)
I'm pretty sure argv[0] won't be an text file.
Give this a try (haven't compiled this, but I've done this a bazillion times, so I'm pretty sure it's at least close):
char* readFile(char* filename)
{
FILE* file = fopen(filename,"r");
if(file == NULL)
{
return NULL;
}
fseek(file, 0, SEEK_END);
long int size = ftell(file);
rewind(file);
char* content = calloc(size + 1, 1);
fread(content,1,size,file);
return content;
}
If you're developing for Linux (or other Unix-like operating systems), you can retrieve the file-size with stat before opening the file:
#include <stdio.h>
#include <sys/stat.h>
int main() {
struct stat file_stat;
if(stat("main.c", &file_stat) != 0) {
perror("could not stat");
return (1);
}
printf("%d\n", (int) file_stat.st_size);
return (0);
}
EDIT: As I see the code, I have to get into the line with the other posters:
The array that takes the arguments from the program-call is constructed this way:
[0] name of the program itself
[1] first argument given
[2] second argument given
[n] n-th argument given
You should also check argc before trying to use a field other than '0' of the argv-array:
if (argc < 2) {
printf ("Usage: %s arg1", argv[0]);
return (1);
}
argv[0] is the path to the executable and thus argv[1] will be the first user submitted input. Try to alter and add some simple error-checking, such as checking if fp == 0 and we might be ble to help you further.
You can open the file, put the cursor at the end of the file, store the offset, and go back to the top of the file, and make the difference.
You can use fseek for text files as well.
fseek to end of file
ftell the offset
fseek back to the begining
and you have size of the file
Kind of hard with no sample code, but fstat (or stat) will tell you how big the file is. You allocate the memory required, and slurp the file in.
Another approach is to read the file a piece at a time and extend your dynamic buffer as needed:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PAGESIZE 128
int main(int argc, char **argv)
{
char *buf = NULL, *tmp = NULL;
size_t bufSiz = 0;
char inputBuf[PAGESIZE];
FILE *in;
if (argc < 2)
{
printf("Usage: %s filename\n", argv[0]);
return 0;
}
in = fopen(argv[1], "r");
if (in)
{
/**
* Read a page at a time until reaching the end of the file
*/
while (fgets(inputBuf, sizeof inputBuf, in) != NULL)
{
/**
* Extend the dynamic buffer by the length of the string
* in the input buffer
*/
tmp = realloc(buf, bufSiz + strlen(inputBuf) + 1);
if (tmp)
{
/**
* Add to the contents of the dynamic buffer
*/
buf = tmp;
buf[bufSiz] = 0;
strcat(buf, inputBuf);
bufSiz += strlen(inputBuf) + 1;
}
else
{
printf("Unable to extend dynamic buffer: releasing allocated memory\n");
free(buf);
buf = NULL;
break;
}
}
if (feof(in))
printf("Reached the end of input file %s\n", argv[1]);
else if (ferror(in))
printf("Error while reading input file %s\n", argv[1]);
if (buf)
{
printf("File contents:\n%s\n", buf);
printf("Read %lu characters from %s\n",
(unsigned long) strlen(buf), argv[1]);
}
free(buf);
fclose(in);
}
else
{
printf("Unable to open input file %s\n", argv[1]);
}
return 0;
}
There are drawbacks with this approach; for one thing, if there isn't enough memory to hold the file's contents, you won't know it immediately. Also, realloc() is relatively expensive to call, so you don't want to make your page sizes too small.
However, this avoids having to use fstat() or fseek()/ftell() to figure out how big the file is beforehand.

File stream is opened but nothing is printed to console. Program doesn't seem to "finish"

I'm new to C and I'm trying to open a file and print its content line by line to console.
The source code is attached along with a couple screen shots to show my situation. (The redded-out part contain my computer's directories and personal info). As you can see from the screenshot, the program prints "before" but not "after". Of course, neither does it print out anything from coc.txt.
I can't figure out why this is the case. Everything seems correct and I don't see any errors.
#include <stdio.h>
#include <stdlib.h> // For exit()
const int MAX_LINE_LENGTH = 300;
int main() {
FILE *inputFile;
inputFile = fopen("coc.txt", "r");
char lineRead[MAX_LINE_LENGTH];
printf("before\n");
while(!feof(inputFile)) {
fgets(lineRead, MAX_LINE_LENGTH, inputFile);
puts(lineRead);
}
fclose(inputFile);
printf("after\n");
}
console
coc.txt
Here's a suggested alternative (not tested yet):
#include <stdio.h>
#define MAX_LINE_LENGTH 300
#define NULL 0
int main(int argc, char *argv[]) {
FILE *inputFile;
char fname[MAX_LINE_LENGTH], lineRead[MAX_LINE_LENGTH];
/* Get filename from cmd-line */
if (argc != 2) {
printf ("USAGE: progname <fname>\n");
return 1;
}
/* Try to open file */
if ((inputFile = fopen("coc.txt", "r")) == NULL) {
perror("Could not open file");
return 2;
}
/* Now read the file, and echo back a line at a time */
printf("before...\n");
while(fgets(lineRead, MAX_LINE_LENGTH, inputFile) != NULL) {
printf ("%s", lineRead);
}
printf("\n...after\n");
/* Cleanup and exit */
fclose(inputFile);
return 0;
}
Changes:
Be sure to have a "return" from main ().
In general, a graceful "return" from main() is preferred over a system call to "exit()".
Read the input, then to check for EOF (fgets() == NULL).
Make sure you've opened the file before reading.
Rather than hard-coding the filename, we're reading it from the command line.
Rather than puts() (which always appends a newline, regardless of whether the string already has a newline), we're using printf().
Make sure that the coc.txt file and the read.c files are in the same folder. I executed your original code and it works fine with VS 2017 on windows 10.

Check if a file is empty or not

How can I check if a text file has something written or not. I tried:
LOGIC checkfile(char * filename)
{
FILE *pf;
pf=fopen(filename,"wt");
fseek(pf,0,SEEK_END);
if(ftell(pf)==0)
printf("empty");
}
This function returns empty everytime, even in my text file I have few words or numbers written.
The problem is that you opened the file for writing. When you do that, everything in the file is lost, and the length of the file is truncated to 0.
So you need to open the file for reading. And the easiest way to see if the file is empty is to try to read the first character with fgetc. If fgetc returns EOF, then the file is empty.
First of all: DO NOT OPEN THE FILE FOR WRITING!
second: for knowing about file status in C you can use fstat which is in sys headear file!
You can use struct stat for using this function
here is a simple example:
#include <sys/stat.h>
int main(void)
{
int fields = 0;
int size = 0;
// Open the file test.txt through open()
// Note that since the call to open directly gives
// integer file descriptor so we used open here.
// One can also use fopen() that returns FILE*
// object. Use fileno() in that case to convert
// FILE* object into the integer file descriptor
if(fields = open(file_path, "r")){
struct stat buf;
fstat(fields, &buf);
size = (int)buf.st_size;
}
printf("size of file is %d", size);
return 0;
}
Note: I just include a header file that related to fstat. You can add other header files yourself
What about using fscanf to read the file, and check if something was actually read?
FILE *fp;
char buff[255] = "";
fp = fopen(filename, "r");
fscanf(fp, "%s", buff);
if (!*buff)
printf("Empty\n");
else
printf("%s\n", buff);
fclose(fp);

file NULL not being forgotten by loop - C

I'm trying to check a directory for a file. I've done that properly. But I'm having trouble for exceptions--> when the file is not there. Here's what I am wanting to do: I 'd like to check for the file, if it exists, then exit the loop. If the file does not exist, then sleep. After sleeping for 3 seconds, check for the file again. Repeat until the file is found then return to main() and print "Hello everyone".
Currently, if the file is missing and i put the file into this directory while the program is running, it never recognizes the new file until i stop the program then start it back up. I want the program to check for the file again after sleep.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <unistd.h>
#define MYFILE "/Users/stackoverflow/Documents/fileabc123"
int checkfile() {
FILE *pFile;
pFile = fopen(MYFILE,"r");
char file_string[40];
int repeat = 0;
while( repeat < 1) {
if (pFile!=NULL) {
fgets (file_string,36,pFile);
fclose (pFile);
printf("%s\n", file_string);
repeat = 1 ;
}
if (pFile ==NULL) {
printf("Machine cannot read system file. \n");
sleep(3);
}
}
}
int main (int argc, char ** argv) {
checkfile();
printf("Hello everyone\n");
return 0;
}
You need to put the fopen in the loop.
if ((pFile = fopen(MYFILE, "r")) != NULL) {
// read it
}
else {
printf("Failed opening");
}
The error is in the loop.
you simply aren't trying to open the file again :)
this give you 2 error:
1. if you put the file it is not seen, as the program does not try to open it
2. if the file is present, you read it, then you close it, leaving an INVALID file descriptr but that is NOT null
this mean next loop you will try to read an invalid file descriptor. It is like reading/writing value with a overflow index from an array, or from a free() pointer.
You will almost always have the right value.. until that ram is reallocated.
so:
1. you have to try to open a file, until you get a valid file descriptor.
2. close will not change pointer value. It simply can't, think about it.
if you whant to change the value of somthing, you have to give it's address. A pointer is the adress of somthing. So File* is pointing to a File, but if you want to change the address pointed by File*, you need it's address (&pFile), just like a scanf :)

Using fseek with a file pointer that points to stdin

Depending on command-line arguments, I'm setting a file pointer to point either towards a specified file or stdin (for the purpose of piping). I then pass this pointer around to a number of different functions to read from the file. Here is the function for getting the file pointer:
FILE *getFile(int argc, char *argv[]) {
FILE *myFile = NULL;
if (argc == 2) {
myFile = fopen(argv[1], "r");
if (myFile == NULL)
fprintf(stderr, "File \"%s\" not found\n", argv[1]);
}
else
myFile = stdin;
return myFile;
}
When it's pointing to stdin, fseek does not seem to work. By that, I mean I use it and then use fgetc and I get unexpected results. Is this expected behavior, and if so, how do I move to different locations in the stream?
For example:
int main(int argc, char *argv[]) {
FILE *myFile = getFile(argc, argv); // assume pointer is set to stdin
int x = fgetc(myFile); // expected result
int y = fgetc(myFile); // expected result
int z = fgetc(myFile); // expected result
int foo = bar(myFile); // unexpected result
return 0;
}
int bar(FILE *myFile) {
fseek(myFile, 4, 0);
return fgetc(myFile);
}
Yes, it's perfectly normal that fseek won't work on stdin -- it'll normally only work on a disk file, or something reasonably similar.
Though it's really a POSIX thing, you can typically use if (isatty(fileno(myFile))) to get at least a pretty good idea of whether seeking will work in a particular file. In some cases, isatty and/or fileno will have a leading underscore (e.g., IIRC the versions provided with Microsoft's compilers do).
Fseek() is based on lseek(), and the lseek man page discusses possible errors, including:
[ESPIPE] Fildes is associated with a pipe, socket, or FIFO.
If stdin is connected to a pseudo tty, I believe it will have socket behavior.
Here is the relevant entry in the ANSI standard concerning the fseek function:
For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET
So, possible but with some limitations

Resources