Запись «битов» в файловые потоки C ++ - PullRequest
11 голосов
/ 19 марта 2010

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

Можно ли записать в очередь и затем очистить ее?

Возможно лиC # или Java?

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

Ответы [ 7 ]

13 голосов
/ 19 марта 2010

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

byte b;
int s;

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

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

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

8 голосов
/ 19 марта 2010

Вы можете использовать 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).

3 голосов
/ 19 марта 2010

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

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

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

Вот код 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)
0 голосов
/ 19 марта 2010

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

Обычный метод для работы с отдельными битами - это упаковать их в наименьшее портативное и (адресуемое) доступное устройство. Неиспользуемые биты обычно устанавливаются в ноль. Это может быть выполнено с помощью двоичных арифметических операций (ИЛИ, И, ИСКЛЮЧИТЕЛЬНО-ИЛИ, НЕ и т. Д.).

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

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

0 голосов
/ 19 марта 2010

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

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

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

0 голосов
/ 19 марта 2010

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

0 голосов
/ 19 марта 2010

Вы не можете на самом деле.Я почти уверен, что проблема не в языке или файловой системе, а в аппаратной проблеме.Процессоры предназначены для работы с байтами.Вероятно, самое близкое, что вы можете сделать, это записать свой последний байт снова и снова, заполнить нулями вправо, меняя их по ходу, по одному за раз.ниже (пример на 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()

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...