Reading and editing a file bit by bit

Basically what I am looking for is a way to get a block memory, copy it into ram in a format along the line of bit[#], replace the original with a new code that may or may not be the same size(they will be something to ensure does not try to save a fraction of a byte).

Is there an easy way to do this or do I just need to read work from a bin file?


If anybody wants to know, this is for school project, and it is just a proof of concept; it does not need to be very optimized.
Accessing a single bit is messy; for instance how does one insert or erase a bit in a sequence of bits?

Perhaps the simplest way is to work with the bits logically, say, a sequence of '0' and '1' chars. These can be easily modified. std::string and std::bitset<> can do the heavy lifting; using them makes our code quite simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <limits>
#include <bitset>
#include <string>
#include <iostream>
#include <fstream>
#include <algorithm>

// http://en.cppreference.com/w/cpp/language/type_alias
using byte = unsigned char ;

// http://en.cppreference.com/w/cpp/types/numeric_limits
constexpr std::size_t BITS_PER_BYTE = std::numeric_limits<byte>::digits ;

// http://en.cppreference.com/w/cpp/utility/bitset
using bits_in_byte = std::bitset<BITS_PER_BYTE> ;

std::string read_bits( const char* path_to_file )
{
    std::string bitstring ;
    std::ifstream file( path_to_file, std::ios::binary ) ; // open in binary mode

    char c ;
    while( file.get(c) ) // read byte by byte
        bitstring += bits_in_byte( byte(c) ).to_string() ; // append as string of '0' '1'

    return bitstring ;
}

void write_bits( std::string bitstring, const char* path_to_file )
{
    // pad with zeroes to make it represent an integral multiple of bytes
    while( bitstring.size()% BITS_PER_BYTE ) bitstring += '0' ;

    std::ofstream file( path_to_file, std::ios::binary ) ; // open in binary mode

    for( std::size_t i = 0 ; i < bitstring.size() ; i += BITS_PER_BYTE )
    {
        // convert each sequence of '0' or '1' to a byte
        byte b = bits_in_byte( bitstring.substr( i, BITS_PER_BYTE ) ).to_ulong() ;
        file << b ; // and write it
    }
}

int main()
{
     // read this file as a string of bits
     std::string bits = read_bits( __FILE__ ) ;
     std::cout << bits << '\n' ;

     // flip every hundredth bit
     for( std::size_t i = 0 ; i < bits.size() ; i += 100 )
     {
         if( bits[i] == 0 ) bits[i] = '1' ;
         else bits[i] = '0' ;
     }

     bits += "011001010110111001100100001" ; // append another 27 bits

     write_bits( bits, "main.cc.mangled" ) ;

     std::cout << std::ifstream("main.cc.mangled").rdbuf() ;
}

http://coliru.stacked-crooked.com/a/40a2ac2f52449a23
Thinks for the help, but I think I figured out a way(I will probably use your to test mine). String format is just way to big; if I opened even a 100Kb file in that it would be close a GB of ram.

Here is what I have so far(incomplete and untested)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>


int checkBit(char c, int n) {
    return c & (1 << n);
}

void setBit(char *c, int n) {
    *c |= 1 << n;
}

class memBlock
{
    private:
    char *mem;
    unsigned long length;

    public:
    memBlock(char *data,unsigned long len, unsigned long startingPoint)
    {
        length = len;
        mem = new char[length-startingPoint];
        for(unsigned long index = startingPoint; index < length;index++)
            mem[index] = data[index]; //copy the data
    }
    memBlock(char *data, unsigned long len)
    {
        length = len;
        mem = new char[length];
        for(unsigned long index = 0; index < length;index++)
            mem[index] = data[index]; //copy the data

    }
    ~memBlock()
    {
        delete mem;
    }

    int GetBit(unsigned long index)
    {
        unsigned long byteIndex = index/8;//get the byte to read
        unsigned long bitIndex = index%8; //get the bit to read
        if(byteIndex > length)
            return -1;
        else
            return  mem[byteIndex] & (1 << bitIndex);
    };
    void SetBit(unsigned long index)
    {
        unsigned long byteIndex = index/8;//get the byte to read
        unsigned long bitIndex = index%8; //get the bit to read
        if(!(byteIndex > length))
        mem[byteIndex] |= 1 << bitIndex;
    };

};



int main()
{

}


> if I opened even a 100Kb file in that it would be close a GB of ram.

It would be 1.6 MB (worst-case, 100K * 8 * 2 ).


> String format is just way to big;

std::vector<bool> is the compact option.
http://en.cppreference.com/w/cpp/container/vector_bool
Topic archived. No new replies allowed.