How do I determine if a file is empty? The file is opened by a C program running on the Windows platform. I want to open a file in append mode, and, if empty, first print a header to it.
// Open CSV & write header
report_csv = fopen("SNR.csv", "a+");
if (!report_csv) {
fprintf(stderr, "Unable to open CSV output file...");
return -1;
}
if (!ftell(report_csv)) {
fprintf(report_csv, "Column A;Column B;Column C\n");
}
// ... print data to file
fclose(report_csv);
I was expecting ftell to return the current file size if the file was not empty, which happens because the code above is looped.
However, ftell always returns 0 and the header is printed multiple times.
I know I could fopen it with r and use fseek/ftell/fclose and then fopen it again with a+, but I think it's possible to do this without opening and closing the file multiple times.
Actually, when fopening a file in append mode, the file pointer is initially at the begining of the file. It moves to the end of it as soon as you write something or use fseek.
I just needed to add fseek(report_csv, 0, SEEK_END); before my if (!ftell(report_csv)).
Let's check this.
Code:
#include <stdio.h>
int main(int argc, char **argv) {
FILE *test;
size_t size;
char buf[100];
/* Truncate file */
test = fopen("test", "w");
if (!test) {
fprintf(stderr, "Cannot open file `test`!\n");
return 1;
}
/* Write something */
fprintf(test, "Something. ");
fclose(test);
/* Open in append */
test = fopen("test", "a+");
if (!test) {
fprintf(stderr, "Cannot open `test` in append mode!\n");
return 1;
}
/* Try to get the file size */
size = ftell(test);
printf("File pointer is: %d\n", size);
fseek(test, 0, SEEK_END);
size = ftell(test);
printf("After `fseek(test, 0, SEEK_END)`, the file pointer is: %d\n", size);
/* Append */
fprintf(test, "And that. ");
fclose(test);
/* Same without fseek */
test = fopen("test", "a+");
if (!test) {
fprintf(stderr, "Cannot open `test` in append mode!\n");
return 1;
}
fprintf(test, "Hello! ");
size = ftell(test);
printf("File size is now: %d\n", size);
fclose(test);
/* Try to read */
test = fopen("test", "r");
if (!test) {
fprintf(stderr, "Unable to open `test` for reading!\n");
return 1;
}
printf("File contents:\n\t");
while (test && !feof(test)) {
fgets(buf, sizeof(buf), test);
printf("%s", buf);
}
/* Cleanup & exit */
fclose(test);
printf("\n\nExiting.\n");
return 0;
}
Output:
File pointer is: 0
After `fseek(test, 0, SEEK_END)`, the file pointer is: 11
File size is now: 28
File contents:
Something. And that. Hello!
Exiting.
When opening a file with fopen with the a+ mode, all writing operations will be performed at the end of the file. You can reposition the internal pointer to anywhere in the file for reading, but writing operations will move it back to the end of file. The initial pointer position for reading is at the beginning of the file.
So you need to call an fseek(pFile, 0, SEEK_END) on your FILE pointer.
You can call _stat() and get the value st_size into struct _stat (you dont need open the file).Declared in sys/types.h followed by sys/stat.h
I don´t know Windows programming, but it can help you: http://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
Related
I'm new to programming in C, doing some work on a MIDI recording program that plays back the notes, and can't seem to get the program to read from the file into my structure array.
Here's the structure:
typedef struct
{
int noteNumber;
int vel;
int oscillatorNumber;
float freq;
} oneNote;
And here's the code to read the notes in:
oneNote notes[2000];
for (count = 0; count < fileSize; count++)
{
fscanf(filePointer, "%d %d %d\n", ¬es[count].noteNumber,
¬es[count].vel,
¬es[count].oscillatorNumber);
notes[count].freq = ntof(notes[count].noteNumber);
}
Code where file is opened:
filePointer = fopen("noteRecordFile.txt", "r");
if (filePointer == NULL)
{
printf("Error opening file\n");
}
else
{
printf("File opened\n");
fseek(filePointer, 0L, SEEK_END);
fileSize = ftell(filePointer);
}
Just doesn't store the and of the data in the structure, as can be seen here:
Image of debug console
First few lines of noteRecordFile.txt:
48 108 0
50 108 0
52 100 0
There are several issues:
Remove following 2 lines, because it puts the file pointer to the end of the file and we want to start the reading at the start of the file, and ftell will give you the number of bytes in the file and not the number of lines.
fseek(filePointer, 0L, SEEK_END);
fileSize = ftell(filePointer);
Then you need this:
FILE *filePointer = fopen("noteRecordFile.txt", "r");
if (filePointer == NULL)
{
printf("Error opening file\n");
exit(1); // <<< abort program if file could not be opened
}
else
{
printf("File opened\n");
}
int count = 0;
do
{
fscanf(filePointer, "%d %d %d", ¬es[count].noteNumber,
¬es[count].vel,
¬es[count].oscillatorNumber);
notes[count].freq = ntof(notes[count].noteNumber);
count++;
}
while (!feof(filePointer)); // <<< read until end of file is reached
...
We cannot know the number of lines the file contains without reading the whole file, so we use a different approach: we just read until the end of the file is reached.
You still need to add a check, because if the file contains more than 2000 lines, you will run into trouble. This is left as an exercise to the reader.
It won't because you reached the end of the file on the line:
fseek(filePointer, 0L, SEEK_END);
you need to reset the file pointer to the beginning of the file:
fseek(filePointer, 0L, SEEK_SET)
Are you sure about your file format ?
As i see, you read the header too as a normal data line...
Try reading this, maybe it'll help you.
MIDI
You can try openning the file as binary, i remember it fixed an issue i had on some sound files...!
Do you have any error/warning during compilation and execution ?
I have a source file file1 and a destination file file2, here I have to move content from file1 to file2.
So I have to do some validation first.
I must check source file is existing or not?
I can check using this:
fp = fopen( argv[1],"r" );
if ( fp == NULL )
{
printf( "Could not open source file\n" );
exit(1);
}
Then I have to check if the source file has any content or not? If it is empty, I have to throw some error message.
This is what I've tried until the moment.
C version:
if (NULL != fp) {
fseek (fp, 0, SEEK_END);
size = ftell(fp);
if (0 == size) {
printf("file is empty\n");
}
}
C++ version (stolen from here):
bool is_empty(std::ifstream& pFile)
{
return pFile.peek() == std::ifstream::traits_type::eof();
}
You can do this without opening the file as well using the stat method.
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
struct stat stat_record;
if(stat(argv[1], &stat_record))
printf("%s", strerror(errno));
else if(stat_record.st_size <= 1)
printf("File is empty\n");
else {
// File is present and has data so do stuff...
}
So if the file doesn't exist you'll hit the first if and get a message like: "No such file or directory"
If the file exists and is empty you'll get the second message "File is empty"
This functionality exists on both Linux and Windows, but on Win it's _stat. I haven't tested the windows code yet, but you can see examples of it here.
Just look if there's a character to read
int c = fgetc(fp);
if (c == EOF) {
/* file empty, error handling */
} else {
ungetc(c, fp);
}
fseek(fp, 0, SEEK_END); // goto end of file
if (ftell(fp) == 0)
{
//file empty
}
fseek(fp, 0, SEEK_SET); // goto begin of file
// etc;
reference for ftell and example
reference for fseek and example
You can use fseek using SEEK_END and then ftell to get the size of a file in bytes.
you can check if the file size > 0
after your code of checking file exist (before you close the file) you add the following code
size = 0
if(fp!=NULL)
{
fseek (fp, 0, SEEK_END);
size = ftell (fp);
rewind(fp);
}
if (size==0)
{
// print your error message here
}
It is painful to open the data and count each byte of the file. It is better to ask to the operating system to give you details about the files you want to used. The API relies depends on your operating system as Mike previously said.
I am try to write a buffer so I can remove a lot of null "00" characters in a file. The characters are useless and are completely random. They are wreaking havoc on the searcher in the program. The code below compiles but just seems to hang when a file is passed to it. Any suggestions will be helpful.
void ReadFile(char *name)
{
FILE *dbg;
char *buffer;
unsigned long fileLen;
//Open file
dbg = fopen(dbg, "w+");
if (!dbg)
{
fprintf(stderr, "Unable to open file %s", name);
return;
}
//Get file length
fseek(dbg, 0, SEEK_END);
fileLen = ftell(dbg);
fseek(dbg, 0, SEEK_SET);
//Allocate memory
buffer = (char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(dbg);
return;
}
//Read file contents into buffer
fread(buffer, fileLen, 1, dbg);
for(i = fileLen-1; i >= 0 && buffer[i] == 0; i--);
i++;
if (i > 0)
{
fwrite(buffer, 1, i, dbg);
}
fclose(dbg);
//Do what ever with buffer
free(buffer);
}
Change
dbg = fopen(dbg, "w+");
to
dbg = fopen(name, "w+");
Also, if you want to read the file, change it then write it, you shouldn't open it with "w+". You should first open the file with "r", read from it, do whatever change you want, then fclose it, then again open it but this time with "w" so that you write over it. After you have opened it in "w"rite mode, you can write the modified buffer back into the file.
You opened a file for writing and then you try to read from it.
Check the return value of fread and all the other calls.
In my code below, the file is being written correctly as far as I can tell. When I look in the file floats.dat I see this stream of binary ÍÌL#33c#ÍÌÜ#ffFAßOeA^#^#bBf6zE33äCff<83>BÍ̦B
However my program always ends up triggering this if statement:
if(fread(inputFloats, sizeof(float), LENGTH, binaryFile) < LENGTH)
{
fprintf(stderr, "Problem reading some or all data from %s\n\n", binaryFileName);
return EXIT_FAILURE;
}
Does anybody see something I've done wrong here? Full code below.
#include <stdlib.h>
#include <stdio.h>
#define LENGTH 10
int main(void)
{
FILE *binaryFile, *textFile;
char *binaryFileName = "floats.dat", *textFileName = "floats.txt";
float floats[LENGTH] = {3.2, 3.55, 6.9, 12.4, 14.332, 56.5, 4003.4, 456.4, 65.7, 83.4};
float inputFloats[LENGTH];
int i;
if((binaryFile = fopen(binaryFileName, "r+")) == NULL)
{
fprintf(stderr, "Problem opening %s", binaryFileName);
}
if(fwrite(floats, sizeof(float), LENGTH, binaryFile) < LENGTH)
{
fprintf(stderr, "Problem writing some or all data to %s\n", binaryFileName);
return EXIT_FAILURE;
}
printf("DATA WRITTEN SUCCESSFULLY\n");
if(fread(inputFloats, sizeof(float), LENGTH, binaryFile) < LENGTH)
{
fprintf(stderr, "Problem reading some or all data from %s\n\n", binaryFileName);
return EXIT_FAILURE;
}
for(i = 0; i < LENGTH; i++)
{
printf("float[%d] = %f\n", i, floats[i]);
}
return EXIT_SUCCESS;
}
You're not working with text data so you should specify a binary mode when opening the file. Use r+b instead of r+
You need to fseek(binaryFile, 0, SEEK_SET) to "rewind" the file after writing. rewind can also be used for this case - fseek allows you to position the read/write pointer wherever you want.
The FILE structure keeps a record of where in the file it is currently pointing. Since you've just written to binaryFile, the file pointer is at the end of what you've written.
You therefore need to rewind the file, using fseek(binaryFile, 0, SEEK_SET); before you read.
You forgot to rewind your file before reading it:
rewind(binaryFile);
When you finish writing to the file, the FILE pointer is at the end of it, so of course if you try reading it will not work. Try using fseek to move the pointer to the beginning of the file before reading.
Please avoid this :
if((binaryFile = fopen(binaryFileName, "r+")) == NULL) {
and prefer this:
binaryFile = fopen(binaryFileName, "rb+");
if(!binaryFile) {
I am using a basic C code to print to a text file:
FILE *file;
file = fopen("zach.txt", "a+"); //add text to file if exists, create file if file does not exist
fprintf(file, "%s", "This is just an example :)\n"); //writes to file
fclose(file); //close file after writing
printf("File has been written. Please review. \n");
My question is regarding the above code: I have multiple lines I have printed that I would like to be saved to the text document. How can I easily include multiple lines of code to be printed in my file using the above code?
Move file writing into a procedure:
void write_lines (FILE *fp) {
fprintf (file, "%s\n", "Line 1");
fprintf (file, "%s %d\n", "Line", 2);
fprintf (file, "Multiple\nlines\n%s", "in one call\n");
}
int main () {
FILE *file = fopen ("zach.txt", "a+");
assert (file != NULL); // Basic error checking
write_lines (file);
fclose (file);
printf ("File has been written. Please review. \n");
return 0;
}
There are lots of ways to do this, here's one:
#include<stdio.h>
#include<string.h>
int appendToFile(char *text, char *fileName) {
FILE *file;
//no need to continue if the file can't be opened.
if( ! (file = fopen(fileName, "a+"))) return 0;
fprintf(file, "%s", text);
fclose(file);
//returning 1 rather than 0 makes the if statement in
//main make more sense.
return 1;
}
int main() {
char someText[256];
//could use snprintf for formatted output, but we don't
//really need that here. Note that strncpy is used first
//and strncat used for the rest of the lines. This part
//could just be one big string constant or it could be
//abstracted to yet another function if you wanted.
strncpy(someText, "Here is some text!\n", 256);
strncat(someText, "It is on multiple lines.\n", 256);
strncat(someText, "Hooray!\n", 256);
if(appendToFile(someText, "zach.txt")) {
printf("Text file ./zach.txt has been written to.");
} else {
printf("Could not write to ./zach.txt.");
}
return 0;
}
notice the strncpy and strncat functions since you aren't really utilizing the formatted input that comes with the xprintf functions.