2010-03-19 8 views
11

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

+0

Вы пропустили какой-либо язык? Большинство языков не позволяют писать меньше байта за раз. Вы можете протестировать отдельные биты и напечатать результаты. – dirkgently

ответ

13

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

byte b; 
int s; 

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

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

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

+0

Выглядит хорошо. В последнем случае можно было бы обрабатывать аргумент 'bool flush' и' if (s == 8 || flush) 'test. –

+0

Просто убедитесь, что s инициализирован равным 0. –

+1

Обратите также внимание на то, что ни один «первый» или «последний» бит в байте не определен или не подразумевается в стандарте C, просто самый или наименее значимый, возможно, «левый» и «правый», как это относится к сдвигам. Таким образом, WriteBit должен сам решить (и документ), должны ли биты быть записаны наиболее или наименее значимыми в первую очередь. Вы пошли наименее значимым, что достаточно справедливо, и Wikipedia утверждает, что он на сегодняшний день наиболее распространен на аппаратном уровне для последовательных коммуникаций. Я никогда не делал это достаточно глубоко, чтобы последовательный драйвер знал сам. –

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) 
0

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

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

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

FYI, языки C и C++ не имеют возможности для объявления двоичных констант. –

0

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

+0

, если я хочу сжать огромный файл, например глифные данные otf arabic. его размер составляет 48 МБ, после того, как копирование составляет 29 МБ. поэтому ваш метод не является теоретическим. и уничтожает память. –

+1

Вы неправильно поняли мой метод. Я просто предлагаю буфер больше байта, чтобы сделать промывку гораздо менее частым, а не буфером, чтобы вместить все ваши данные. – Tronic

0

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

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

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

8

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

0

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

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

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

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