Read and write to binary files in C? - c

Does anyone have an example of code that can write to a binary file. And also code that can read a binary file and output to screen. Looking at examples I can write to a file ok But when I try to read from a file it is not outputting correctly.

Reading and writing binary files is pretty much the same as any other file, the only difference is how you open it:
unsigned char buffer[10];
FILE *ptr;
ptr = fopen("test.bin","rb"); // r for read, b for binary
fread(buffer,sizeof(buffer),1,ptr); // read 10 bytes to our buffer
You said you can read it, but it's not outputting correctly... keep in mind that when you "output" this data, you're not reading ASCII, so it's not like printing a string to the screen:
for(int i = 0; i<10; i++)
printf("%u ", buffer[i]); // prints a series of bytes
Writing to a file is pretty much the same, with the exception that you're using fwrite() instead of fread():
FILE *write_ptr;
write_ptr = fopen("test.bin","wb"); // w for write, b for binary
fwrite(buffer,sizeof(buffer),1,write_ptr); // write 10 bytes from our buffer
Since we're talking Linux.. there's an easy way to do a sanity check. Install hexdump on your system (if it's not already on there) and dump your file:
mike#mike-VirtualBox:~/C$ hexdump test.bin
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0001 003e 0001 0000 0000 0000 0000 0000
...
Now compare that to your output:
mike#mike-VirtualBox:~/C$ ./a.out
127 69 76 70 2 1 1 0 0 0
hmm, maybe change the printf to a %x to make this a little clearer:
mike#mike-VirtualBox:~/C$ ./a.out
7F 45 4C 46 2 1 1 0 0 0
Hey, look! The data matches up now*. Awesome, we must be reading the binary file correctly!
*Note the bytes are just swapped on the output but that data is correct, you can adjust for this sort of thing

There are a few ways to do it. If I want to read and write binary I usually use open(), read(), write(), close(). Which are completely different than doing a byte at a time. You work with integer file descriptors instead of FILE * variables. fileno will get an integer descriptor from a FILE * BTW. You read a buffer full of data, say 32k bytes at once. The buffer is really an array which you can read from really fast because it's in memory. And reading and writing many bytes at once is faster than one at a time. It's called a blockread in Pascal I think, but read() is the C equivalent.
I looked but I don't have any examples handy. OK, these aren't ideal because they also are doing stuff with JPEG images. Here's a read, you probably only care about the part from open() to close(). fbuf is the array to read into,
sb.st_size is the file size in bytes from a stat() call.
fd = open(MASKFNAME,O_RDONLY);
if (fd != -1) {
read(fd,fbuf,sb.st_size);
close(fd);
splitmask(fbuf,(uint32_t)sb.st_size); // look at lines, etc
have_mask = 1;
}
Here's a write: (here pix is the byte array, jwidth and jheight are the JPEG width and height so for RGB color we write height * width * 3 color bytes). It's the # of bytes to write.
void simpdump(uint8_t *pix, char *nm) { // makes a raw aka .data file
int sdfd;
sdfd = open(nm,O_WRONLY | O_CREAT);
if (sdfd == -1) {
printf("bad open\n");
exit(-1);
}
printf("width: %i height: %i\n",jwidth,jheight); // to the console
write(sdfd,pix,(jwidth*jheight*3));
close(sdfd);
}
Look at man 2 open, also read, write, close. Also this old-style jpeg example.c: https://github.com/LuaDist/libjpeg/blob/master/example.c I'm reading and writing an entire image at once here. But they're binary reads and writes of bytes, just a lot at once.
"But when I try to read from a file it is not outputting correctly." Hmmm. If you read a number 65 that's (decimal) ASCII for an A. Maybe you should look at man ascii too. If you want a 1 that's ASCII 0x31. A char variable is a tiny 8-bit integer really, if you do a printf as a %i you get the ASCII value, if you do a %c you get the character. Do %x for hexadecimal. All from the same number between 0 and 255.

I'm quite happy with my "make a weak pin storage program" solution. Maybe it will help people who need a very simple binary file IO example to follow.
$ ls
WeakPin my_pin_code.pin weak_pin.c
$ ./WeakPin
Pin: 45 47 49 32
$ ./WeakPin 8 2
$ Need 4 ints to write a new pin!
$./WeakPin 8 2 99 49
Pin saved.
$ ./WeakPin
Pin: 8 2 99 49
$
$ cat weak_pin.c
// a program to save and read 4-digit pin codes in binary format
#include <stdio.h>
#include <stdlib.h>
#define PIN_FILE "my_pin_code.pin"
typedef struct { unsigned short a, b, c, d; } PinCode;
int main(int argc, const char** argv)
{
if (argc > 1) // create pin
{
if (argc != 5)
{
printf("Need 4 ints to write a new pin!\n");
return -1;
}
unsigned short _a = atoi(argv[1]);
unsigned short _b = atoi(argv[2]);
unsigned short _c = atoi(argv[3]);
unsigned short _d = atoi(argv[4]);
PinCode pc;
pc.a = _a; pc.b = _b; pc.c = _c; pc.d = _d;
FILE *f = fopen(PIN_FILE, "wb"); // create and/or overwrite
if (!f)
{
printf("Error in creating file. Aborting.\n");
return -2;
}
// write one PinCode object pc to the file *f
fwrite(&pc, sizeof(PinCode), 1, f);
fclose(f);
printf("Pin saved.\n");
return 0;
}
// else read existing pin
FILE *f = fopen(PIN_FILE, "rb");
if (!f)
{
printf("Error in reading file. Abort.\n");
return -3;
}
PinCode pc;
fread(&pc, sizeof(PinCode), 1, f);
fclose(f);
printf("Pin: ");
printf("%hu ", pc.a);
printf("%hu ", pc.b);
printf("%hu ", pc.c);
printf("%hu\n", pc.d);
return 0;
}
$

This is an example to read and write binary jjpg or wmv video file.
FILE *fout;
FILE *fin;
Int ch;
char *s;
fin=fopen("D:\\pic.jpg","rb");
if(fin==NULL)
{ printf("\n Unable to open the file ");
exit(1);
}
fout=fopen("D:\\ newpic.jpg","wb");
ch=fgetc(fin);
while (ch!=EOF)
{
s=(char *)ch;
printf("%c",s);
ch=fgetc (fin):
fputc(s,fout);
s++;
}
printf("data read and copied");
fclose(fin);
fclose(fout);

I really struggled to find a way to read a binary file into a byte array in C++ that would output the same hex values I see in a hex editor. After much trial and error, this seems to be the fastest way to do so without extra casts. By default it loads the entire file into memory, but only prints the first 1000 bytes.
string Filename = "BinaryFile.bin";
FILE* pFile;
pFile = fopen(Filename.c_str(), "rb");
fseek(pFile, 0L, SEEK_END);
size_t size = ftell(pFile);
fseek(pFile, 0L, SEEK_SET);
uint8_t* ByteArray;
ByteArray = new uint8_t[size];
if (pFile != NULL)
{
int counter = 0;
do {
ByteArray[counter] = fgetc(pFile);
counter++;
} while (counter <= size);
fclose(pFile);
}
for (size_t i = 0; i < 800; i++) {
printf("%02X ", ByteArray[i]);
}

this questions is linked with the question How to write binary data file on C and plot it using Gnuplot by CAMILO HG. I know that the real problem have two parts: 1) Write the binary data file, 2) Plot it using Gnuplot.
The first part has been very clearly answered here, so I do not have something to add.
For the second, the easy way is send the people to the Gnuplot manual, and I sure someone find a good answer, but I do not find it in the web, so I am going to explain one solution (which must be in the real question, but I new in stackoverflow and I can not answer there):
After write your binary data file using fwrite(), you should create a very simple program in C, a reader. The reader only contains the same structure as the writer, but you use fread() instead fwrite(). So it is very ease to generate this program: copy in the reader.c file the writing part of your original code and change write for read (and "wb" for "rb"). In addition, you could include some checks for the data, for example, if the length of the file is correct. And finally, your program need to print the data in the standard output using a printf().
For be clear: your program run like this
$ ./reader data.dat
X_position Y_position (it must be a comment for Gnuplot)*
1.23 2.45
2.54 3.12
5.98 9.52
Okey, with this program, in Gnuplot you only need to pipe the standard output of the reader to the Gnuplot, something like this:
plot '< ./reader data.dat'
This line, run the program reader, and the output is connected with Gnuplot and it plot the data.
*Because Gnuplot is going to read the output of the program, you must know what can Gnuplot read and plot and what can not.

#include <stdio.h>
#include <stdlib.h>
main(int argc, char **argv) //int argc; char **argv;
{
int wd;
FILE *in, *out;
if(argc != 3) {
printf("Input and output file are to be specified\n");
exit(1);
}
in = fopen(argv[1], "rb");
out = fopen(argv[2], "wb");
if(in == NULL || out == NULL) { /* open for write */
printf("Cannot open an input and an output file.\n");
getchar();
exit(0);
}
while(wd = getw(in), !feof(in)) putw(wd, out);
fclose(in);
fclose(out);
}

Related

Writing even integers up to n in a file in c, putw() function error

I'm writing a program that will output all even integers up to 100 in a text file.
Here's the whole code:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int main() {
FILE *fp;
int i;
if ((fp = fopen("even_up_to_100.txt", "w")) == NULL) {
perror("Write");
exit(1);
}
for (i = 1; i <= MAX; ++i) {
if (!(i % 2))
putw(i, fp);
}
fclose(fp);
if ((fp = fopen("even_up_to_100.txt", "r")) == NULL) {
perror("Read");
exit(2);
}
while (!feof(fp))
printf("%d ", getw(fp));
fclose(fp);
return 0;
}
OUTPUT(from text file):
" $ & ( * , . 0 2 4 6 8 : < > # B D F H J L N P R T V X Z \ ^ ` b d
OUTPUT(from console window):
2 4 6 8 10 12 14 16 18 20 22 24 -1
Please point out the error(if there's any) in the code with the solution.
Inside the text file there are some control characters, which are shown as blank spaces here.
Since getw/putw are binary I/O functions, you should be opening your file in binary mode ("wb" instead of "w" as the mode argument to fopen, and likewise "rb" instead of "r").
Character 26 is ASCII Ctrl-Z, which Windows (and DOS before it) use as an end-of-file marker for text files. So if you're on such a system, when you attempt to read the number 26 from your file, the library sees a Ctrl-Z byte and treats that as the end of the file. That would explain why your program stops reading after 24. Opening in binary mode disables this behavior, and will also avoid various other problems, e.g. the handling of CR characters.
Note that if your goal was, as you said, to "output all even integers up to 100 in a text file", then getw/putw are the wrong tools for the job as they do binary I/O, not text. (Even if you did want binary format, you should not use getw/putw but rather fread/fwrite, as I explain here.) If you want to create a text file, with human-readable contents, you should use fprintf and fscanf.

Two processes writing on the same file

I know this is recipe for disaster. And I actually made it work using shared variables.
But it's homework, and teacher definitely wants us to put many processes writing to the same file using different file pointers. I've been trying all day with little success, but I just can't find why this fails.
I have approached the problem in the folowing way:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int status;
int process_count = 0;
do
{
int from = (n / np) * (process_count) + 1;
int to = (n / np) * (process_count + 1);
if (fork() == 0)
{
FILE *aux;
aux = fopen("./parciais.txt", "w");
fseek(aux, sizeof(int) * process_count, SEEK_SET);
int sum = 0;
int i = from;
while (i <= to)
{
int square = i * i;
sum += square;
i++;
}
long int where_am_i = ftell(aux);
printf("I am process %i writing %i on byte: %li\n", process_count, sum, where_am_i);
fwrite(&sum, sizeof(int), 1, aux);
fclose(aux);
exit(1);
}
else
{
wait(&status);
process_count++;
}
} while (process_count < np);
FILE *aux;
aux = fopen("./parciais.txt", "r");
int sum;
for (int i = 0; i <= np - 1; i++)
{
fseek(aux, sizeof(int) * i, SEEK_SET);
long int where_am_i = ftell(aux);
int read;
fread(&read, sizeof(int), 1, aux);
printf("I am reading %i at byte: %li\n", read, where_am_i);
sum += read;
}
}
I expected the output to be something such as:
I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 98021 at byte: 0
I am reading 677369 at byte: 4
I am reading 1911310 at byte: 8
But I get:
I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 0 at byte: 0
I am reading 0 at byte: 4
I am reading 1911310 at byte: 8
This means, for some reason, only the last value is written.
I've been banging my head on the wall over this and I just can't find where's the catch... Can someone please lend me a hand?
The problem is due to fopen("./parciais.txt", "w") :
"w" : "Creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file."
Try with "a" instead!
("Appends to a file. Writing operations, append data at the end of the file. The file is created if it does not exist.")
As mentioned in another answer, the "a" argument is not enough either. The file must be created once, hence in the main process, and then accessed in "r+b" mode for the fseek to work correctly!
As #B.Go already answered, the main problem is that you are opening the file with mode "w", which truncates it to zero length if it already exists. Each child process does this, clobbering the contents written by the previous one.
You want this combination of behaviors for the file:
it is created if it does not already exist (or I suppose you want this, at least)
it is not truncated upon opening if it does already exist
you may write to it
writes start at the current file offset, as opposed to automatically going to the current end of the file
the file is binary, not subject to any kind of character translation or to tail truncation upon writing to it
Unfortunately, there is no standard mode that provides all of it: the various r modes require that the file already exist, the w modes truncate the file if it does already exist, and the a modes direct all writes to the current end of the file, regardless of the stream's current offset. If you can assume that the file will already exist then mode "r+b", which can also be spelled "rb+", has all the wanted characteristics except creating the file if it doesn't exist:
aux = fopen("./parciais.txt", "r+b");
That permits reading as well, but just because you can read from the file doesn't mean you have to do. Additionally, on Linux and POSIX-conforming systems, there is no distinction between binary and text files, so you can omit the b if you are confident that your program needs to run only on POSIX systems. That you are using fork() suggests that this condition may apply to you.
If you must provide for creating the file, too, then open it once at the very beginning of the program, using any of the w or a modes depending on whether you want to truncate the file, then immediately close it again:
FILE *aux = fopen("./parciais.txt", "a");
if (aux) {
fclose(aux);
} else {
// handle error ...
}

Copying and Converting a File to Binary File in C with System Calls

I'm currently working on a program that has to duplicate any file into a binary file using system calls ( open(), write(), read() etc... ). This is what have so far.
void copyFileToFD(int destinationFD, int sourceFD){
unsigned char b[64];
int amountRead = -1;
while((amountRead = read(sourceFD, &b, 64)) > 0){
int written = write(destinationFD, &b, amountRead);
}
}
The problem I'm having right now is with text files.
Suppose a file has this text:
This is some text 12345678
My current output file shows
This is some text 12345678
MY desired output file ()
ABCD EF00 0000 0000 0000 0000...
How can I change my code so that all files will be copied as a binary file
I am aware of fread() and fwrite() but would like to know how this can be done with system calls.
Thanks for any help.
It appears that you want to translate the input into hexadecimal text output. You can do it using printf():
void copyFileToFD(int destinationFD, int sourceFD){
unsigned char ch;
ssize_t amountRead = -1;
while((amountRead = read(sourceFD, &ch, sizeof(ch))) > 0){
dprintf(destinationFD, "%.2x ", ch);
}
}

Confusion in file Verification with CRC16 in C

Here i want to know the how can i implement calculate CRC16 for Any type of file,
Here i have idea about CRC16 and its code logic.
here i made one function which take file path as a input and find out CRC value of this. here i pass file name in this function and this functions calculates CRC value of this file. but i want to calculate all types of files like .tar,.tar.gz,.txt,.bin,.scr etc.
so here i open this all files and "rb" mode and take one by one character and find out CRC value
its right way? may be i missing something in this. its works fine for .txt and all other files but it will create problems in .tar, .tar.gz type files. Because here i have one file which is 890 MB and its name is file.tar.gz and its take 203 Microseconds and I have other file which is 382 MB and its name is file2.tar its take 6097850.000000 Microseconds its unbelievable for me hows its possible?
My question are these
1 Some thing problem in my CRC code ?
2 Problem in reading file data style, may be i am reading file data in wrong manner for .tar.gz.
Here is my code :
int CRC16(const char* filePath) {
//Declare variable to store CRC result.
unsigned short result;
//Declare loop variables.
int intOuterLoopIndex, intInnerLoopIndex, nLen;
result = 0xffff; //initialize result variable to perform CRC checksum calculation.
//Store message which read from file.
//char content[2000000];
//Create file pointer to open and read file.
FILE *readFile;
//Use to read character from file.
char readChar;
//open a file for Reading
readFile = fopen(filePath, "rb");
//Checking file is able to open or exists.
if (!readFile) {
fputs("Unable to open file %s", stderr);
}
/*
Here reading file and store into variable.
*/
int chCnt = 0;
while ((readChar = getc(readFile)) != EOF) {
result ^= (short) (readChar);
for (intInnerLoopIndex = 0; intInnerLoopIndex < 8; intInnerLoopIndex++) {
if ((result & 0x0001) == 0x0001) {
result = result >> 1; //Perform bit shifting.
result = result ^ 0xa001; //Perform XOR operation on result.
} else {
result = result >> 1; //Perform bit shifting.
}
}
//content[chCnt] = readChar;
chCnt++;
}
printf("CRC data length in file: %d", chCnt);
return (result);
}
char readChar; is wrong, it needs to be int readChar;
getc() returns an int, so it can signal EOF to you. EOF is likely the value -1
If you convert the return value to a char, and read a byte with the value 255, 255 will be interpreted as -1, and you stop reading at the first byte that has the value 255.
This code is wrong in different points:
if (!readFile) {
fputs("Unable to open file %s", stderr);
}
If the file opening fails you don't return but continue! And the puts is wrong also, you don't specify the file name.
Also, getc() returns an integer, but you put it in a char and it may end just when it finds an EOF character! Don't ignore compiler warnings...
I would download a small CRC calculator program, so that you can test if your code is working properly.

Reading binary files in C, on UNIX systems (Ubuntu 10.10)

this is my first time programming in C, and on a UNIX system. I am trying to do something fairly simple. I have a binary file that is an image of a Compact Flash camera card, and consists of a few JPG images. I am trying to read through the file, find the byte sequence corresponding to FF D8 FF E0, or FF D8 FF E1, the signifiers of the beginning of a JPG file, then writing everything between that signifier and the next to a new jpg file.
At the moment I am just trying to get my computer to print out the file as is, by reading it in 512 size blocks, the stated size of the blocks in the original file system. I have the following code:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main (int argc, char *argv[])
{
FILE * raw;
FILE * currentimage;
char buf[512];
char beg1[32] = "11111111110110001111111111100001";
char beg2[32] = "11111111110110001111111111100000";
raw = fopen("card.raw", "rb");
while((fread(buf, sizeof(raw), 512, raw) > 0))
{
printf(buf);
printf("\n");
}
}
It just prints out the file formatted into what I presume is ASCII, so it looks like a bunch of gobbledegook. How can I get this data formatted to either binary 1's and 0's or, even better, hex 0-F's?
Any help would be much appreciated.
P.S. beg1 and beg2 correspond to the binary values of the hex values I am looking for, but they are not really relevant to the rest of the code I have at the moment.
Instead of printf(buf); you would need to loop through each byte and do printf("%02x ", byte). Take a look at the source of hexdump here:
http://qa.coreboot.org/docs/doxygen/hexdump_8c_source.html
You should read up on what printf() does, as in NO PROGRAMMING LANGUAGE that I know, should you EVER use data as the first argument to printf. The first argument should be a template, which the way you used it should be "%s". To see hex output, replace your loop with this:
int size;
while((size = (fread(buf, sizeof(raw), 512, raw)) > 0))
{
for (int i = 0; i < size; i++)
{
printf("%2X", buf[i]);
}
printf("\n");
}
To answer your question about comparision in C before printing:
The numerical data is right there in buf -- buf[i] is an char from -127 to 128 that contains the value. If you want to look at its hex representation, you can do:
sprintf(some_other_buffer, "%2X", buf[i]);
Then you can perform string manipulation on some_other_buffer, knowing it's a 2 character string.

Resources