优化函数将位写入文件

时间:2010-12-05 14:47:48

标签: c++ file-io bit-manipulation

这是一个将n位写入二进制文件的函数。

参数:

  • 数据:要写入文件的位序列(右侧的lsb)
  • 长度:要写入的位数
  • OutFile:目标文件。

第一版的功能:

void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
    static unsigned long long BitBuffer = 0;
    static unsigned BitCounter = 0;

    for (unsigned i = Length; i --; ) {
        (BitBuffer <<= 1) |= ((Data >> i) & 0x1);
        BitCounter ++;

        if (BitCounter == 64) {
            OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
            BitCounter = 0;
        }
    }
}

第二版:

void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
    static unsigned long long BitBuffer = 0;
    static unsigned FreeBitCounter = sizeof(BitBuffer) << 3;

    Data &= (1 << Length) - 1;

    if (FreeBitCounter > Length) {
        BitBuffer |= (Data << (FreeBitCounter -= Length));
    } else if (FreeBitCounter < Length) {
        BitBuffer |= (Data >> (Length -= FreeBitCounter));
        OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
        BitBuffer = Data << ((sizeof(BitBuffer) << 3) - Length);
        FreeBitCounter = (sizeof(BitBuffer) << 3) - Length;
    } else {
        BitBuffer |= Data;
        OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
        BitBuffer = 0; FreeBitCounter = (sizeof(BitBuffer) << 3);
    }
}

他们都做了这个工作,但第二个比第一个快。有什么想让它更快?

谢谢大家的帮助!

6 个答案:

答案 0 :(得分:1)

  1. 我首先要删除静态 函数体中的变量。 他们有点慢,应该测试 他们的状态(已经初始化或 不)每个函数调用。只是 将它们移出功能范围。

  2. 为什么要使用这么短的缓冲区?您确定需要将每个unsigned long long写入文件吗?我建议使用像unsigned char buffer[1024]这样的东西。

  3. 然后你应该考虑如何摆脱其他“如果陈述”。

答案 1 :(得分:1)

而不是write()来电,请尝试以下方法:

OutFile.rdbuf()->sputn((char *) & BitBuffer, sizeof(BitBuffer));

答案 2 :(得分:0)

打开文件可能比写入文件要慢得多。在您的设计中,您是否最小化文件打开调用?

答案 3 :(得分:0)

如果我理解正确,你想要写下你收到的无符号长整数的低位length。您可以通过屏蔽所需的位来保存通过输入位的循环:

unsigned long long mask = (1ull << length) - 1; // creates a mask of 'length' 1's
BitBuffer = Data & mask;

作为评论,我不明白为什么你的测试和写作在第一个版本的循环中。

答案 4 :(得分:0)

首先,您需要编写代码以使其易于理解。我无法轻易理解您的任何代码片段。这是尝试重新格式化和重构第一个更简单,并添加一些注释:

/**
 * @brief Write some bits to a file.
 *
 * The bits are written MSB-first to a temporary 64-bit integer, which is
 * then written to the file in host byte-order.
 *
 * @param Data The data to write to the file.  Only the least-significant
 *             Length bits are written.  Of the bits that are written, the
 *             most significant bit is written first.
 * @param Length The length of the data to write, in bits.  Must be <= 64.
 * @param OutFile The file to write to
 *
 * @note This function is not thread-safe
 * @note This function stores some state in a static variable.  You must
 *       ensure that the total data written is a multiple of 64 bits, or
 *       some data will be lost.  You can only switch from one OutFile to
 *       another on a 64-bit boundry.
 */
void WriteBitsToFile(unsigned long long Data,
                     unsigned Length,
                     std::ofstream & OutFile)
{
   static unsigned long long BitBuffer = 0;
   static unsigned BitCounter = 0; 

   // Loop through input bits, one bit at a time
   for (int i = (int)Length; i >= 0; --i)
   {
      // Get the input bit
      unsigned long long NextBit = ((Data >> i) & 1);

      // Add it to the temporary buffer
      BitBuffer = ((BitBuffer << 1) | NextBit);
      BitCounter++;

      // If the temporary buffer is full, write it out
      if (BitCounter == 64)
      {
         OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
         BitCounter = 0;
      }
   }
}

现在我明白你要做什么......

你的第二个版本看起来好多了,因为你正在避免每位循环。既然你要求优化这个,我假设你有分析结果表明这很慢?而且我假设您通过此方式提供了大量数据?

一种可能的优化是写入更大的缓冲区(我建议至少4kB)。这意味着您不需要经常调用write()。调用write()可能会相对较慢。

答案 5 :(得分:0)

这是使用更大缓冲区的一种方法。 (在Pseudo-C#中)

const int wordSz= sizeof(unsigned long long)*8;

void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) { 
   static unsigned long long BitBuffer[BUFSZ+1] ={0};  
   static unsigned bitsSoFar = 0;

   Data &= (1 << Length) - 1; 
   int index = bitsSoFar/wordSz;
   int offset = bitsSoFar - (index*wordSz);
   BitBuffer[index]|=Data<<offset;
   int remainder = offset+length-wordSz;
   if (remainder > 0)
   {
      index++;
      BitBuffer[index]=Data>>(length-remainder);
   }
   bitsSoFar+=length;
   if (bitsPacked > BUFSZ*wordSz)
   {
      OutFile.write((char*)BitBuffer, BUFSZ*sizeof(unsigned long long));
      bitsSoFar-=BUFSZ*wordSz;
      BitBuffer[0]=BitBuffer[BUFSZ];
   }
}