Read a binary file C programming - c

I'm doing a program to manage a clinic, but I'm having a problem. I need to read a binary file with the information from the Doctors. The information is name, code and telephone. They are inserted by the user.
How can I printf that info separately. For example:
Name: John Cruz
Code: JC
Telephone: 90832324
I'm trying to use
typedef struct {
char code[10];
char name[100];
int telephone;
} DOCTOR;
int newDoctor() {//This is the function that create the binary file
DOCTOR d;
FILE *fp;
fp = fopen("Doctors.dat","wb");
if(fp==NULL) {
printf("Error!");
return -1;
}
printf("Code\n");
fflush(stdin);
gets(d.code);
printf("Name\n");
gets(d.name);
printf("Telephone\n");
scanf("%d",&d.telephone);
fprintf(fp,"%s;%s;%d",d.code,d.name, d.telephone);
fclose(fp);
}
//And to open
FILE* fp;
fp=fopen("Doctors.dat","rb");
while(!EOF(fp)) {
fgets(line, 100, fp);
printf("%s",line);
}
Just to see the line but it's not working, and how i can separate the info?
Regards

fgets assumes that the data is ascii strings. For binary data you need to know the binary format and read the data into the appropriate data structures.

You must know the format the binary is in, such as if you serialized a previous struct then you can read it into a struct of the same type:
typedef struct
{
int stuff;
double things;
} myStruct;
myStruct writeMe = {5, 20.5};
FILE* fp;
fp = fopen("Doctores.dat","wb");
if (fp == NULL) { fputs ("File error", stderr); exit(EXIT_ERROR); }
fwrite(writeMe, 1, sizeof(writeMe), fp);
fclose(fp);
Then later to read:
myStruct readMe;
FILE* fp2;
fp2 = fopen("Doctores.dat","rb");
if (fp2 == NULL) { fputs ("File error", stderr); exit(EXIT_ERROR); }
fread(readMe, 1, sizeof(readMe), fp2);
fclose(fp2);
printf("my int: %i\nmy double: %f", readMe.stuff, readMe.things);
Hope this helps

There are at least two issues here: file & data format and reading a binary file. File format is how the information is organized within the file. Binary reading involves reading the file without any translations.
File and Data Format
For text fields, you need to know the following:
Fixed or variable length field.
Maximum field width.
Representation (null terminated,
fixed length, padded, preceded by
length of string, etc.)
You can't assume anything. Get the format in writing. If you don't understand the writing, have the original author rewrite the documentation or explain it to you.
For integral numeric fields you need to know the following:
Size of number, in bytes.
Endianness: Is first byte the Most
Significant (MSB) or Least
significant (LSB)?
Signed or Unsigned
One's complement or two's complement
Numbers can range from 1 "byte" to at least 8 bytes, depending on the platform. If your platform has a native 32-bit integer but the format is 16-bit, your program will read 16 extra bits from the next field. Not good; bad, very bad.
For floating point: you need to know the representation.
The are many ways to represent a floating point number. Floating point numbers can very in size also. Some platforms use 32-bits, while others use 80 bits or more. Again, assume nothing.
Binary Reading
There are no magic methods in the C and C++ libraries to read your structure correctly in one function call; you will have to assemble the fields yourself. One thorn or bump is the fact that compilers may insert "padding" bytes between fields. This is compiler dependent and the quantity of padding bytes is not standard. It is also known as alignment.
Binary reading involves using fread or std::istream::read. The common method is to allocate a buffer, read a block of data into the buffer, then compose the structures from that buffer based on the file format specification.
Summary
Before reading a binary stream of data, you will need a format specification. There are various ways to represent data and internal data representation varies by platform. Binary data is best read into a buffer, then program structures and variables can be built from the buffer.
Textual representations are simpler to input. If possible, request that the creator of the data file use textual representations of the data. Field separators are useful too. A language like XML helps organize the textual data and provides the format in the data file (but may be too verbose for some applications).

Related

C: unsigned short stored into buffer after fread from a binary file doesn't match original pattern

I have a binary file filled with 2-byte words following this pattern(in HEX): 0XY0. this is the part of the code where I execute fread and fopen.
unsigned short buffer[bufferSize];
FILE *ptr; //
ptr = fopen(fileIn,"rb"); //
if(ptr == NULL)
{
fprintf(stderr,"Unable to read from file %s because of %s",fileIn,strerror(errno));
exit(20);
}
size_t readed = fread(buffer,(size_t)sizeof(unsigned short),bufferSize,ptr);
if(readed!=bufferSize)
{
printf("readed and buffersize are not the same\n");
exit(100);
}
//---------------------------
If I look at any content of the buffer, for example buffer[0], instead of being a short with pattern 0XY0, it is a short with pattern Y00X
Where is my error? is it something regarding endianess?
of course i checked every element inside buffer. the program execute with no errors.
EDIT: If i read from file with size char instead of short, the content of buffer(obviously changed to char buffer[bufferSize*2];) match the pattern OXYO. So I have that (for example) buffer[0] is 0X and buffer[1] is Y0
Your problem seems to be exactly typical of an endianness mismatch between the program that stored the data into the file and the one that reads it. Remember that mobile phone processors tend to use big-endian representations and laptop little-endian.
Another potential explanation is your file might have been written in text mode by a windows based program that converted the 0x0A bytes into pairs of 0x0D / 0x0A, causing the contents to shift and cause a similar pattern as what you observe.
Instead of reading the file with fread, you should read it byte by byte and compute the values according the endianness specified for the file format.

Most efficient way to write a number in a file in C?

I need to keep trace of an int number greater than 255 in a file. It is greater than the largest unsigned char and so the use of the fputc seems to be not reliable (first question: is it always true?).
I could use fputs, by converting the digits in characters, so obtaining a string; but in the program i need the number as an int too!
So, the question in the title: what is so the most efficient way to write that number? Is there any way to avoid the conversion to string?
Keep that the file should then be readed by another process, where char number should become an int again.
Just write out the binary representation:
int fd;
...
int foo = 1234;
write (fd, &foo, sizeof(foo));
(and add error handling).
Or if you like FILE*
FILE *file;
...
int foo = 1234;
fwrite (&foo, sizeof(foo), 1, file);
(and add error handling).
Note that if your file is to be loaded on a different system, potential with different endianness, you might want to ensure the endianness of the bytes is constant (e.g. most significant byte or least significant byte first). You can use htnol, htons etc. for this if you want. If you know the architecture that is loading the file is the same as that saving it, there is no need for this.

how to read from binary file into struct c?

i have the following struct
struct
{
char order;
int row;
int column;
int length;
char printChar;
}record;
and my file look's like this
F
30
40
7
X
how can i use fread to store the file in the struct?
does my file appear correctly or should all the components need to be in one-line?
If I understand correctly, you're asking if you can do
struct record r;
fread(file, &r, sizeof(r));
or are you forced to use
struct record r;
fread(file, &r.order, sizeof(r.order));
If this is your question, then the answer is: you have to read the fields one-by-one since there may be padding between struct members. Or, if you use a GNU-compatible compiler, you might instruct it not to include any padding by declaring your struct as "packed":
struct record {
// ...
} __attribute__((packed));
But this is not advised unless absolutely necessary (it's not portable).
Also, is your file really a binary file? If not, you should pay attention to newline characters and converting the numbers from text to their actual numeric value.
It is not possible to read from a file in that format (essentially containing the character representations of the data) into the structure. One method for reading it would be to use fgets and read each line and assign the data into the structure (converting numeric values as necessary with functions such as strtol or perhaps atoi if error checking is not as important).
Your file seems to be a text file, so if that's exactly the format of the file, you can use fscanf:
fscanf(file, "%c%d%d%d%c", &(record.order), &(record.row), ...
You can check the return value if you're interested in basic error handling. If you need a better description of the error, just use fgets to read one line at a time and parse it with sscanf, atoi, strtol and similar functions.
If you want to directly save data in the structure, no, you can't (with that kind of file), in a text file 30 is a string of two characters, not an integer in binary form.

Conversion from binary file to hex in C

I am trying to write some simple program to uploading files to my server. I' d like to convert binary files to hex. I have written something, but it does not work properly.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int bufferSize = 1024;
FILE *source;
FILE *dest;
int n;
int counter;
int main() {
unsigned char buffer[bufferSize];
source = fopen("server.pdf", "rb");
if (source) {
dest = fopen("file_test", "wb");
while (!feof(source)) {
n = fread(buffer, 1, bufferSize, source);
counter += n;
strtol(buffer, NULL, 2);
fwrite(buffer, 1, n, dest);
}
}
else {
printf("Error");
}
fclose(source);
fclose(dest);
}
I use strtol to convert binary do hex. After invoking this code I have still strange characters in my file_test file.
I' d like to upload a file on server, for example a PDF file. But firstly I have to write a program, that will convert this file to a hex file. I'd like that the length of a line in hex file would be equal 1024. After that, I will upload this file line by line with PL/SQL.
EDIT: I completely misunderstood what the OP was aiming for. He wants to convert his pdf file to its hex representation, as I see now, because he wants to put that file in a text blob field in some database table. I still claim the exercise is a complete waste of time,since blobs can contain binary data: that's what blobs were invented for. Blob means binary large object.
You said: "I' d like to upload file on server, for example pdf file. But firstly I have to write a program, that will convert this file to hex file."
You don't have to, and must not, write any such conversion program.
You have to first understand and internalize the idea that hex notation is only an easy-to-read representation of binary. If you think, as you seem to, that you have to "convert" a pdf file to hex, then you are mistaken. A pdf file is a binary file is a binary file. You don't "convert" anything, not unless you want to change the binary!
You must abandon, delete, discard, defenestrate, forget about, and expunge your notion of "converting" any binary file to anything else. See, hex exists only as a human-readable presentation format for binary, each hex digit representing four contiguous binary digits.
To put it another way: hex representation is for human consumption only, unsuitable (almost always) for program use.
For an example: suppose your pdf file holds a four-bit string "1100," whose human-readable hex representation can be 'C'. When you "convert" that 1100 to hex the way you want to do it, you replace it by the ASCII character 'C', whose decimal value is 67. You can see right away that's not what you want to do and you immediately see also that it's not even possible: the decimal value 67 needs seven bits and won't fit in your four bits of "1100".
HTH
Your code is fantastically confused.
It's reading in the data, then doing a strtol() call on it, with a base of 2, and then ignoring the return value. What's the point in that?
To convert the first loaded byte of data to hexadecimal string, you should probably use something like:
char hex[8];
sprintf(hex, "%02x", (unsigned int) buffer[0] & 0xff);
Then write hex to the output file. You need to do this for all bytes loaded, of course, not just buffer[0].
Also, as a minor point, you can't call feof() before you've tried reading the file. It's better to not use feof() and instead check the return value of fread() to detect when it fails.
strtol converts a string containing a decimal representation of a number to the binary number if i am not mistaken. You probably want to convert something like a binary OK to 4F 4B... To do that you can use for example sprintf(aString, "%x", aChar).

InternetReadFile() corrupting downloads in C

I'm able to download text documents (.html, .txt, etc) but I can't download images or exe's. I'm pretty sure that this is because I'm using a char, and those files are binary. I know that in C# I would use a byte. But what data-type would I use in this case?
char buffer[1];
DWORD dwRead;
FILE * pFile;
pFile = fopen(file,"w");
while (InternetReadFile(hRequest, buffer, 1, &dwRead))
{
if(dwRead != 1) break;
fprintf(pFile,"%s",buffer);
}
fclose(pFile);
Your problem is not char, it is using fprintf with %s. char can hold all byte values. When a binary data chunk has a \0 (NULL) character in it, fprintf will stop outputting data at that time.
You want to use fwrite in this case.
In Windows, it is also important to use the b specifier when opening binary files.
Since you are reading one byte at a time into a buffer which is not null terminated (because its size is 1), you need to output one byte at a time with either '%c' as the format string or using putc(buffer[0], pFile). As it stands, you are vulnerable to buffer overflow (as in, bad things may happen!).
If you are on a Windows platform, it would be a good idea to open the file in binary mode; it would do no harm on Unix since there is no difference between binary and text mode.

Resources