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 ?
Related
I'm writing a program that asks the user for a file name, and creates it if it doesn't exist. At the end of the program, I want to check if the created program is empty, and if it is, delete it. Not deleting it and then running the program with that same file name messes up the way the input is detected.
I've tried using rewind() to go back to the beginning and then checking feof() to see if the beginning of the file was the EOF character, but that didn't work.
Then, I did some searching online, and found a method that used fseek() to go to the end of the file, and then checked with ftell() whether the end of the file was at position 0, but again this did not work.
I went back and did more poking around, and found that the problem might be because I hadn't used fclose() first, so I tried the previous two attempted solutions again, this time being sure to close the file before trying to delete it. Still no dice.
I tried checking what errno was set to, and got 2: No such file or directory. This is patently false, since if that was the case, it would mean that I had accomplished my goal, and when I check the working directory, the file is still there.
I have absolutely no idea what to try next. Can anyone point me in the right direction?
Here are the ways I've tried to delete the file (fp is the file pointer, and file is a char pointer with the name of the file that fp points to.) :
Attempt 1:
rewind(fp);
if(feof(fp)){
remove(file);
}
Attempt 2:
fseek(fp, 1, SEEK_END);
long size = ftell(fp);
if(size == 0){
remove(file);
}
Attempt 3:
fseek(fp, 1, SEEK_END);
long size = ftell(fp);
fclose(fp);
if(size == 0){
remove(file);
}
Attempt 4:
rewind(fp);
int empty = 0;
if(feof(fp)){
empty = 1;
}
fclose(fp);
if(empty == 1){
remove(file);
}
UPDATE: Here's a couple MCVEs, one for each method.
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp;
char file[40];
scanf(" %[^\n]s", file);
fp = fopen(file, "r");
if(fp == NULL){
fp = fopen(file, "w");
int result;
rewind(fp);
int empty = 0;
if(feof(fp)){
empty = 1;
}
fclose(fp);
if(empty == 1){
result = remove(file);
}
printf("%d\n", result);
printf("%d\n", errno);
return 0;
}
Version 2:
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp;
char file[40];
scanf(" %[^\n]s", file);
fp = fopen(file, "r");
if(fp == NULL){
fp = fopen(file, "w");
int result;
fseek(fp, 1, SEEK_END);
long size = ftell(fp);
fclose(fp);
if(size == 0){
result = remove(file);
}
printf("%d\n", result);
printf("%d\n", errno);
return 0;
}
UPDATE 2:
I just realized that when I was making the MCVEs, when I ran them, result was returning 0, which should have meant that it was successful, but the file was still there in the directory. I'm at a loss for words.
The code wasn't reaching the remove statement.
I have written this void function to check input files being read are valid, but there is one thing I don't know how to implement.
fseek and ftell are used to determine if a file is empty or not, but if a file is full of spaces or tabs, it will count as not being empty (though it is).
The input files will either contain integers and/or word strings.
So is there a way to check if the whole file has any ints or strings or otherwise only contains blank spaces?
I imagine I might have to use either scanf_s or gets, with isspace...
FILE *inp;
/* Checks to see if file can be read */
errCode = fopen_s(&inp, file_location, "r");
if (errCode != 0) {
printf(" ERROR. File %s was not located, ensure the following directory is valid: %s\n\n ", file_name, file_location);
*file_Error = ERROR;
return;
}
/*Move to end of file*/
fseek(inp, 0, SEEK_END);
/*Set filesize to size at end of file*/
fileSize = ftell(inp);
/*Print error and exit if filesize is zero i.e. contains 0 bytes (no data)*/
if (fileSize == 0) {
fclose(inp);
printf(" ERROR. File %s contains no data. (File size = %d bytes)\n\n ", file_name, fileSize);
*file_Error = ERROR;
return;
}
/*Print error and exit if filesize is zero for .dats containing only spaces or \t i.e. contains 0 bytes (no data)*/
/*Reset to beginning of file for reading*/
fseek(inp, 0, SEEK_SET);
/* Checks for error reading file occured */
if (errCode != 0) {
printf(" Error opening file %s.\n\n ", file_name);
*file_Error = ERROR;
return;
}
/*if no error on file*/
else
{
printf_s(" File %s Opened.\n\n", file_name);
*file_Error = 0;
}
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.
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
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.