Writing bits to a file in C

20,312

Solution 1

All filesystems¹ deal with files in terms of bytes (and allocate storage space with a much larger granularity, 512 bytes at a time minimum). There's no way you are going to get a file that is 3 bits long.

The best you can do is use up one whole byte but ignore 5 of its bits. To do that (assuming that the number is always going to fit into a byte), convert the input string to an integral type:

long l = strtol(c, 0, 2);

Then get its least significant byte:

unsigned char b = l & 0xffl;

And write it to the file:

fwrite(&b, 1, 1, binFile);

¹ Well, maybe not all. There might be some researchers somewhere that experiment with bit-sized filesystems. I wouldn't know.

Solution 2

Your output file is 4 bytes in length because you're writing an int to the file. On most platforms, an int is 4 bytes in size.

You won't be able to write less than 1 byte at a time.

Solution 3

What you can do is write it as bits (3) and fill it up to a byte with 0's. However, you also need to start (or end) with the number of bits (or bits from the last byte) that are really used.

E.g. (using first byte as length):

00000011   -> 3, meaning from the last (and only byte in this case, 
              only the first 3 bits are used)
10100000   -> 101 is the string, other 5 bits are 0, just use for padding

In this case the overhead of the first (length) byte is 50%, the longer the string, the less the overhead percentage of course.

Solution 4

2 notes on your approach:

  1. [Modern] Computers can't handle less than 1 byte in memory, so you won't be able to write single bits to disk.

    Also, filesystems usually allocate space in chunks (512 bytes, 1Kb, ...) where the file fits. So, if you have a 500 bytes file, you are actually loosing 512 bytes of disk space.

  2. atoi() doesn't convert from string to binary numbers, but to integer. You are actually writing 0b1100101, which is 0d101. You should do the conversion first. Something like:

    char b = 0;
    for (int i=0; c[i]!=NULL; i++) 
    {
        b = ((b<<1) | atoi(c[i]));
    }
    

Solution 5

You are not writing the bits 101, but the binary value of the decimal number 101, ie 1100101. Because you are fread a size of sizeof(x) bytes, your file will be sizeof(x) bytes long.

Share:
20,312
Francesco Bonizzi
Author by

Francesco Bonizzi

I'm a freelance full stack software developer in my little company: Imagine Software. Author of INFART, Rellow, Starfall. Sites: C# Articles LinkedIn profile My personal website Pluviophile 🌧😁

Updated on November 29, 2020

Comments

  • Francesco Bonizzi
    Francesco Bonizzi over 3 years

    I have this string: "101" I want to write it to a file, in C, not as text: "101" and so 8 bits x char. but directly use the string as bits: the bit "1", the bit "0" and the bit "1", so that the file will be of 3 bits.

    Is it possibile? I searched on the web and I tried doing this:

    char c[25] = "101";
    FILE *binFile = fopen("binFile.bin", "wb");
    int x = atoi(c);
    fwrite(&x, sizeof(x), 1, binFile);
    

    But at the end, when I verify files's bytes, Windows says me that it is 4bytes file! And not 3bits!

    How can I do this, if it is possible? Thanks a lot.