Problems reading a binary file with fread function - c

What I want to do is to read the contents of a '.d' binary file and store them in an array.
So I wrote the following codes:
void viewFile()
{
unsigned char inFileData[SIZE];
char fileName[SIZE];
int numRead;
FILE *inBinFile;
printf("Enter the file name:");
scanf("%s", fileName);
inBinFile = fopen( fileName, "rb");
if(( inBinFile = fopen(fileName, "rb")) == NULL )
{
fprintf( stderr, "Error opening %s\n", fileName );
clearStdin();/*a function to clear stdin*/
mainMenu();/*a function to prompt user input*/
}
numRead = fread( inFileData, sizeof(unsigned char), SIZE, inBinFile );
inFileData[SIZE] = '\0';
printf("U coded data:\n%s\n", inFileData);
printf("%d\n", numRead);
fclose(inBinFile);
return;
}
the output is an unreadable pile of junk. Which part did I do wrong? I don't get it.
also, I wrote my clearStdin function as below:
void clearStdin(void)
{
scanf("%*[^\n]");
scanf("%*1[\n]");
return;
}
compiler reported no errors, but somehow the function call doesn't seem to work exactly the way I wanted. It did clear stdin, but there are always errors closely following wherever this function is called, eg., the mainmenu function to prompt user input.
Please help!! thanks in advance.

"the output is an unreadable pile of junk" - yes, it will be. It's a binary file, it's not meant to be readable as text.
If you want to see binary information in a readable form, think about doing a hex dump of it.
See here for a way to do this.

Related

How to fix &localtime in .txt - C

I want to implement a function in my program that sends a .txt to my email with some tasks that i have to do in the day. Here's the code:
void txtCreator(){
/**file.dat and file.txt, respectively**/
FILE *fp, *fp1;
/**struct that contain the events**/
struct evento *display = (struct evento *)malloc(sizeof(struct evento));
char buffer[48];
char email_events[] = {"dd_mm.txt"};//filename.txt
char msg[]={"Nao ha eventos disponiveis para hoje!\n"};
int count=0;
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
strftime(buffer, 48, "%d_%m", &timenow);
fp = fopen(file_name, "rb");
fp1 = fopen(email_events, "w");
if(strcmp(buffer, email_events)!=0){
strcpy(email_events, buffer);
while(fread(display, sizeof(struct evento), 1, fp)==1){
if (feof(fp) || fp==NULL){
break;
}
else if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1){
fwrite(display, sizeof(struct evento), 1, fp1);
fprintf(fp1, "%s", "\n");
count++;
}
}
}
if(count==0){
fprintf(fp1, "%s", msg);
}
fclose(fp);
fclose(fp1);
}
Everything is working just fine, but there's two problems:
1-
strcpy(email_events, buffer);
is not working, and:
2-
when i create the .txt file, it shows like that:
test ¹0(¹€(.v™ ™­ °'¹8¹uguese_Brazil.12
it shows the event name (test) correctly, but the date is not working.
I've tried a lot of things, but nothing works.
Sorry for the bad english, not my native language.
when i create the .txt file, it shows like that:
test ¹0(¹€(.v™ ™­ °'¹8¹uguese_Brazil.12
Let's address this first: you're not writing text to your .txt file. You're writing a struct. It's going to look like garbage.
For example, let's say display->dia is 19. This means the number 19 will be written to the file, not the text 19, the number 19. Read as text, 19 is garbage. 10 is a newline. 65 is A.
If your intent is to dump the structs into a file, assuming struct evento has no pointers, you're good. In fact you probably shouldn't add a newline, it will interfere with reading the file by the size of the struct.
If your intent is to produce a human readable text file, you need to translate each piece of the struct into text. For example, if you wanted to write the day and month as text...
fprintf(fp1, "%d_%d", display->dia, display->mes);
I'll assume that going forward.
strcpy(email_events, buffer); is not working
At first glance it looks like your strcpy is backwards, it's strcpy(src, dest) and presumably you want to copy email_events into buffer: strcpy(buffer, email_events).
Looking further, your code does nothing with either buffer nor email_events after that. The strcpy is pointless.
Going even further, buffer is the month and day like 07_19. email_events is always dd_mm.txt. Those will never match. strcmp(buffer, email_events)!=0 will always be true making the if check pointless.
I'm not sure what the intent of buffer and email_events are, but it appears to be trying to create a filename based on the current date? This can be done much simpler with one better named variable outfile.
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
char outfile[20];
strftime(outfile, 20, "%d_%m.txt", &timenow);
Moving along to other problems, you don't check that fp1 opened.
You do eventually check fp but you check it after you've already read from a possibly null file pointer. If you're compiling with an address sanitizer (which you should) it will cause an error. Causing an error when using a null pointer is good, it will solve many a mystery memory problem for you.
It's much easier and robust and address sanitizer friendly to check immediately. We can also do a better job naming them to avoid confusing the input from the output: in and out.
FILE *in = fopen(file_name, "rb");
if( in == NULL ) {
perror(file_name);
exit(1);
}
And since you're reading binary with rb you should be writing binary you should be using wb. This only matters on Windows, but might as well be consistent.
FILE *out = fopen(outfile, "wb");
if( out == NULL ) {
perror(outfile);
exit(1);
}
There's no need to check feof(fp), while(fread(display, sizeof(struct evento), 1, fp)==1) will already exit the loop at end of file when it fails to read. In general, explicitly checking for the end of file leads to subtle problems.
The read/write loop is now much simpler.
while(fread(display, sizeof(struct evento), 1, in)==1){
if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1) {
fprintf(out, "%d_%d\n", display->dia, display->mes);
count++;
}
}
Putting it all together...
void txtCreator(){
const char *no_events_found_msg = "Nao ha eventos disponiveis para hoje!\n";
// No need to cast the result of malloc, it just invites mistakes.
struct evento *display = malloc(sizeof(struct evento));
// Generate the output filename directly, no strcmp and strcpy necessary.
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
char outfile[20];
strftime(outfile, 48, "%d_%m.txt", &timenow);
// Immediatetly make sure the files are open and error immediately.
FILE *in = fopen(file_name, "rb");
if( in == NULL ) {
perror(file_name);
exit(1);
}
FILE *out = fopen(outfile, "wb");
if( out == NULL ) {
perror(outfile);
exit(1);
}
// Now that we know the files are open, reading and writing is much simpler.
int count=0;
while(fread(display, sizeof(struct evento), 1, in)==1){
if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1) {
fprintf(out, "%d_%d\n", display->dia, display->mes);
count++;
}
}
if(count==0){
fprintf(out, "%s", no_events_found_msg);
}
fclose(in);
fclose(out);
}
Note that I've used a style which declares variables in place. This makes the code easier to read, limits the scope of each variable, and it avoids declaring variables which you never use.
Assuming that you are meaning to copy email_events into your buffer (since you assigned a static string), your strcpy parameters are backwards.
Below is the declaration of strcpy
char *strcpy(char *dest, const char *src);
You probably meant:
strcpy(buffer, email_events);

C - Printing Bin. File In Weird Symbols

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.

fopen in Mainframe (C language)

I'm working on opening a file from the mainframe. currently, I can't access the input file I wanted. I don't know if there is something wrong with the C code or my JCL. Anyone help me out?
Here is my code:
int main()
{
FILE *ifp, *ofp;
printf("CTRACE1\n");
ifp = fopen("dd:INPUTF", "rb, recfm=vb, lrecl=50");
printf("CTRACE2\n");
ofp = fopen("dd:OUTPUTF","w");
printf("CTRACE3\n");
fread( buffer, sizeof( char ), LINESZ, ifp );
printf( "Number of characters read = %i\n", num );
printf( "buffer = %s\n", buffer );
dstr = (DATASTR*) buffer;
printf("VAR_A = %.*s\n", sizeof(dstr->VAR_A), dstr->VAR_A);
printf("VAR_B = %.*s\n", sizeof(dstr->VAR_B), dstr->VAR_B);
printf("VAR_C = %.*s\n", sizeof(dstr->VAR_C), dstr->VAR_C);
printf("CTRACE4\n");
x[sizeof(x)+1]='\0';
y[sizeof(y)+1]='\0';
z[sizeof(z)+1]='\0';
printf("CTRACE5\n");
memcpy(x, dstr->VAR_A,sizeof(dstr->VAR_A));
memcpy(y, dstr->VAR_B,sizeof(dstr->VAR_B));
memcpy(z, dstr->VAR_C,sizeof(dstr->VAR_C));
printf("CTRACE6\n");
printf("%s,%s,%s",x,y,z);
printf("CTRACE7\n");
fwrite(buffer, sizeof(char), LINESZ, ofp);
fprintf(ofp,"%s,%s,%s\n",x,y,z);
fclose(ifp);
fclose(ofp);
return(0);
}
Here's my JCL:
...
//* TYPRUN=SCAN
//JOBLIB DD DSN=X543863.LOADLIB1,DISP=SHR
//STEP1 EXEC PGM=CCCGRATE
//INPUTF DD DSN=X543863.SAMPLE.INPUT01,DISP=SHR
//OUTPUTF DD DSN=X543863.SAMPLE.OUTPUT01,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(1,1,45)),
// DCB=(RECFM=FB,LRECL=50)
//SYSOUT DD SYSOUT=*
//
add an
#include <errno.h>
rewrite the open() calls to trap errors
if (!ifp = fopen("dd:INPUTF", "rb, recfm=vb, lrecl=50"))
{
perror("ifp");
exit(1);
}
printf("CTRACE2\n");
if (!ofp = fopen("dd:OUTPUTF","w"))
{
perror("ofp");
exit(1);
}
And you should get a clue on why the input file does not work
Without knowing exactly what output you get, at best it is difficult to say.
Are you trying to copy variable-length records to fixed-length records?
Two things. On the fopen for an input file you do not need to specify DCB information - so recfm=vb and lrecl=50 are not needed (the information if not specified, will be taken from the JCL (if present) or from the catalog (which will be correct)).
Since they are not needed, you have probably got them wrong :-)
Take them off, and try your program.
Looking at what you have there and have specified for the output, either the vb is wrong (you are writing an fb) or the 50 is wrong (if you have 50 bytes of data, which you logically have from your fb definition, the the lrecl for a vb should be 54, because four bytes extra to the data are needed to include the RDW (Record Descriptor Word)).
The is nothing wrong with your JCL, but no way to tell whether the files and definitions of files are correct.
Down to you now. If you still can't fix it, provide all the likely information.

How to check if a file exists in C from user input

I'm a complete noob to C and I wondered why if I take a user input why it wont find the file but when I hard code it using:
const char * fn = "/Users/james/Documents/test.rtf";
It seems to work fine?
char text[100];
fputs("File location: ", stdout);
fflush(stdout);
fgets(text, sizeof text, stdin);
FILE *fp = fopen(text,"r");
if( fp ) {
printf("\nFile Exists");
fclose(fp);
} else {
printf("\nFiles doesn't exist");
}
Any help would be awesome, or just a point to some online source that I have clearly not been able to find.
:)
fgets reads a line and keeps the final newline character. You'll have to strip that off by
text[strlen(text) - 1] = '\0';
(After doing the proper error checking, of course.)
You can use access() to check whether file exists or not
For access you need to provide path of the file and mode.
Prototype of access is
int access(const char *pathname, int mode);
access() returns zero if file exists.
For more information visit: http://linux.die.net/man/2/access

Can I pass a string into fopen()? in c

My goal is to gather input and open files based on that input.
FILE*
open_input_file (char* fileName) //opens source file to be read
{
return fopen(fileName, "r");
}
In an earlier function, I collect input from the user and save it to fileName. When I debug the program, it tells me fopen is returning NULL. That's not what I want, and I'm not sure where the problem is.
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
inFile = open_input_file(infileName);
}
I don't know what the problem is. Any thoughts?
If fopen returns NULL, the open failed. errno will hold the failure code and strerror(errno) will return a short description of why the open failed.
#include <errno.h>
#include <string.h>
...
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
if (!(inFile = open_input_file(infileName))) {
fprintf(stderr, "Error opening '%s': %s\n",
infileName, strerror(errno));
} else {
// open successful
...
}
}
Off-topic
gather_input better make sure infileName is null-terminated to prevent buffer overflows. The simplest way to do this is to define the size of the file name buffer as a macro and set the last character to 0.
#define FILENAMELEN 32
void gather_input(char infileName[]) {
...
infileName[FILENAMELEN-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[FILENAMELEN] = {'\0'};
This isn't very flexible. You could instead pass the size of the file name buffer into gather_input.
#define LENGTH(a) (sizeof(a) / sizeof(a[0]))
void gather_input(char infileName[], size_t len) {
...
infileName[len-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName, LENGTH(infileName)); // infileName is an output parameter for this
An alternative to setting the last character, if using standard string manipulation functions, is to use the strl* functions (strlcpy and strlcat) rather than their unbounded cousins. If you aren't using strl*, you should be using strncpy and strncat.
Have you checked that the file pointed to by inFilename exists on your HDD ?
Check the value of infileName in your debugger or put a printf statement to show the value on screen. printf("'%s'\n", infileName);
Did you call fclose() on your file inside the open_input_file() call. Maybe the file is still locked ?
Edit: I just checked the code. I have modified your english_to_morse() function. 1. The while statement is easier to follow than the for. 2. fgetc() returns an int and not a char.
At the top of the initialise I added this. This initialises every string in the array with and undefined string of ".??.". This will make it easier to find strange bugs as everything in your array is at least initialised.
I have modified different sections of the code but you should be able to follow.
initialize_morse_alphanum (char morseStrings[91][6])
{
for (int i=0;i<91;i++)
strcpy(morseStrings[i], ".??.");
....
....
void
english_to_morse(FILE* inputFile, FILE* outputFile, char morseStrings[91][6])
{ int convert;
convert = fgetc(inputFile);
while (convert != EOF)
{
fputs(morseStrings[convert], outputFile);
fputc(' ', outputFile);
printf ("%s ", morseStrings[convert]);
convert = fgetc(inputFile);
}
}
open_output_file (char* fileName) //opens destination file to be written
{ FILE* handle = NULL;
handle = fopen (fileName, "w"); <---- Remove the * from filename
return handle; }
Also, as mentioned in a different answer, it would be good to add some bounds checks to different areas of the code. At the moment it is quite prone to crashing. If my input file contains a lowercase 'a' (ascii 96) your program will be accessing memory that is out of bounds. So you should add a line like if (convert >= '0' && convert <= 'Z') in there somewhere. I will let you work that out.
Make sure that gather_input works properly. Could it be a problem because you're trying to read a file you're also writing on? In this case, try to close and open again the stream.

Resources