Запись 'битов' к потокам файла C++

Как я могу записать 'один бит' в поток файла или файловую структуру каждый раз?

Действительно ли возможно записать в очередь и затем сбросить его?

Действительно ли это возможно с C# или Java?

Это было необходимо при попытке реализовать экземпляр Кодирования методом Хаффмана. Я не могу записать биты в файлы, поэтому запишите им в bitset и затем (когда сжатие было завершено), пишут, 8-разрядная часть его каждый раз (исключите последнее).

11
задан pnuts 22 August 2018 в 11:08
поделиться

7 ответов

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

byte b;
int s;

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

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

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

13
ответ дан 3 December 2019 в 04:31
поделиться

Я делал это однажды для декодирования huffman и в итоге записал биты как символы и таким образом обработал все внутренне как обычную старую строку C.

Таким образом, вам не нужно беспокоиться о байте в конце строки, и она также читается человеком. Также проверка битов становится проще, поскольку это просто вопрос обращения к массиву char (binbuf

== '1'), а не необходимость возиться с битами. Это не самое оптимизированное решение, но оно точно решило мою проблему.

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

0
ответ дан 3 December 2019 в 04:31
поделиться

Вы можете использовать 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 . Это на платформе с прямым порядком байтов (x64).

8
ответ дан 3 December 2019 в 04:31
поделиться

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

поэтому, чтобы записать биты '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()

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

0
ответ дан 3 December 2019 в 04:31
поделиться

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

0
ответ дан 3 December 2019 в 04:31
поделиться

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

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

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

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

0
ответ дан 3 December 2019 в 04:31
поделиться

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

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

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

Вот некоторый код 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)
3
ответ дан 3 December 2019 в 04:31
поделиться