Запись "бит" в потоки файлов С++

Как я могу писать "один бит" в поток файлов или файловую структуру каждый раз? можно ли записать в очередь, а затем сбросить его? возможно ли с С# или java? это было необходимо, когда я пытаюсь реализовать экземпляр Huffman codding. Я не могу записать бит в файлы. поэтому записывайте их в битовый набор, а затем (когда сжатие завершено) каждый раз записывайте 8-битный фрагмент (исключая последний).

Ответ 1

Буферизация отдельных битов, пока вы не накопили целый байт, не кажется хорошей идеей:

byte b;
int s;

void WriteBit(bool x)
{
    b |= (x ? 1 : 0) << s;
    s++;

    if (s == 8)
    {
        WriteByte(b);
        b = 0;
        s = 0;
    }
}

Вам просто нужно иметь дело с случаем, когда количество бит, которое должно быть записано, не кратно восьми.

Ответ 2

Вы можете использовать boost::dynamic_bitset вместе с std::ostream_iterator для достижения желаемого результата в сжатом виде:

#include <fstream>
#include <iterator>
#include <boost/dynamic_bitset.hpp>

typedef boost::dynamic_bitset<unsigned char> Bitset;

// To help populate the bitset with literals */
Bitset& operator<<(Bitset& lhs, bool val) {lhs.push_back(val); return lhs;}

int main()
{
    Bitset bitset;
    bitset<<0<<1<<0<<1<<0<<1<<0<<1
          <<1<<0<<1<<0;

    std::ofstream os("data.dat", std::ios::binary);
    std::ostream_iterator<char> osit(os);
    boost::to_block_range(bitset, osit);

    return 0;
}

Я сделал размер блока моих dynamic_bitset 8 бит, указав unsigned char в качестве параметра шаблона. Размер блока можно увеличить, указав более крупный целочисленный тип.

boost::to_block_range сбрасывает бит в блоках с заданным выходным итератором. Если в последнем блоке есть пустые остаточные бит, они будут заполнены нулем.

Когда я открываю data.dat в шестнадцатеричном редакторе, я вижу: AA 05. Это находится на маленькой платформе endist (x64).

Ответ 3

Какую файловую систему вы используете?

Скорее всего, он хранит длину файла в байтах (есть ли какие-то нет?), поэтому невозможно иметь физический файл, который не является целым числом байтов.

Итак, если вы пишете файл в виде потока бит, вам нужно либо урезать последние несколько бит, когда вы закончите, либо выписать окончательный байт с помощью каких-то сбоев в оставшихся битах.

Здесь приведен код Python, чтобы начать работу

class BitFile(file):
    def __init__(self, filename, mode):
        super(BitFile, self).__init__(filename, mode)
        self.bitCount=0
        self.byte = 0

    def write(self, bit):
        self.bitCount+=1
        self.byte = self.byte*2+bit
        if self.bitCount%8==0:
            super(BitFile, self).write(chr(self.byte))
            self.byte=0

    def close(self):
        if self.bitCount%8!=0:
            super(BitFile, self).write(chr(self.byte))
        super(BitFile, self).close()     

with BitFile("bitfile.bin","w") as bf:
    bf.write(1)
    bf.write(1)
    bf.write(1)
    bf.write(0)
    bf.write(0)
    bf.write(0)
    bf.write(0)
    bf.write(0)
    bf.write(1)

Ответ 4

Ты не можешь. Я уверен, что проблема связана не с языком или файловой системой, а с аппаратной проблемой. Процессоры предназначены для работы с байтами. Вероятно, самое близкое, что вы можете сделать, - это писать свой последний байт снова и снова, правильно дополняясь нулями, меняя их по ходу, по одному за раз.

поэтому для записи битов "11011" вы можете сделать следующее (пример python, но любой язык должен иметь возможности для этого:

f.write(chr(0b10000000))
f.flush()
f.seek(-1)
f.write(chr(0b11000000))
f.flush()
f.seek(-1)
f.write(chr(0b11000000))
f.flush()
f.seek(-1)
f.write(chr(0b11010000))
f.flush()
f.seek(-1)
f.write(chr(0b11011000)) 
f.flush()

Вы не надеялись получить какую-то выгоду от этого, не так ли?

Ответ 5

Я бы рекомендовал выделить довольно большой буфер (по меньшей мере, 4096 байт) и сбросить его на диск всякий раз, когда он заполняется. Использование однобайтового буфера обычно приводит к плохой производительности.

Ответ 6

Я сделал это один раз для декодирования хаффмана и закончил писать биты в виде символов и, таким образом, обрабатывал все внутри себя как обычную старую строку C.

Таким образом, вам не нужно беспокоиться о завершающем байте, и это также понятно для человека. Кроме того, проверка битов проще, поскольку он просто предназначен для адресации массива char (binbuf[123] == '1') вместо того, чтобы играть с битами. Не самое оптимизированное решение, но оно решило мою проблему аккуратно.

Очевидным недостатком является то, что это представление использует больше памяти.

Ответ 7

Проблема в том, что многие платформы не имеют прямого доступа к битам. Они группируют биты в минимальный пакет, часто с байтом или словом. Кроме того, протокол для потоковых устройств не облегчает передачу отдельных битов.

Общим методом обработки отдельных битов является их упаковка в самый маленький портативный и (адресуемый) доступный модуль. Неиспользуемые биты обычно устанавливаются на ноль. Это может быть выполнено с помощью двоичных арифметических операций (OR, AND, EXCLUSIVE-OR, NOT и т.д.).

С современными процессорами бит-скручивание замедляет работу машины и производительность. Память дешевая и с большими адресными пространствами, обоснование для упаковки битов стало более сложным. Как правило, бит-упаковка зарезервирована для аппаратно-ориентированных операций (а также протоколов передачи). Например, если емкость процессора составляет 16 бит, процессор, вероятно, может обрабатывать 16 слов быстрее, чем 16-битные манипуляции одним словом.

Кроме того, имейте в виду, что запись в и из памяти часто быстрее, чем ввод-вывод из потоков. Эффективные данные буфера системы в памяти перед передачей данных. Вы можете рассмотреть эту технику в своих проектах. Сокращение операций ввода-вывода улучшит производительность вашей программы.