连接二进制位大小的字符串

Concatenate binary bit-sized strings

本文关键字:字符串 二进制 连接      更新时间:2023-10-16

我想向文件中写入一系列二进制字符串,这些字符串的长度用位而不是字节表示。考虑二进制形式的两个字符串s1s2,它们分别为011和01011。在这种情况下,输出文件的内容必须是:01101011(1字节)。我正试图以最有效的方式做到这一点,因为我有数百万个字符串要连接,总共输出几个GB。

C++无法直接处理位,因为它的目标是成为一个轻层上面的硬件和硬件本身不是面向位的。最起码的在一次操作中可以读取/写入的位数是一个字节(通常为8位)。

此外,如果您需要进行磁盘i/o,最好将数据写入块中,而不是一次写入一个字节。库有一些缓冲,但缓冲得越早,代码就越快(传递数据所涉及的代码就越少)。

一个简单的方法可以是

unsigned char iobuffer[4096];
int bufsz; // how many bytes are present in the buffer
unsigned long long bit_accumulator;
int acc_bits; // how many bits are present in the accumulator
void writeCode(unsigned long long code, int bits) {
    bit_accumulator |= code << acc_bits;
    acc_bits += bits;
    while (acc_bits >= 8) {
        iobuffer[bufsz++] = bit_accumulator & 255;
        bit_accumulator >>= 8;
        acc_bits -= 8;
        if (bufsz == sizeof(iobuffer)) {
            // Write the buffer to disk
            bufsz = 0;
        }
    }
}

没有最佳的方法来解决你的问题本身。但你可以使用一些技巧来加快速度:

  1. 尝试使用文件I/O同步标志。由于缓冲和缓存的原因,设置/取消设置可能比其他设置快得多
  2. 尝试使用体系结构大小的变量,以便它们直接放入寄存器:uint32_t用于32位机器,uint64_t用于64位机器
  3. "易失性"可能有助于将事物保存在寄存器中
  4. 对大数据使用指针和引用,复制小数据块(以避免不必要的大数据复制以及对小数据的大量查找和页面触摸)
  5. 使用文件的mmap进行直接访问,并将输出与架构和硬盘的页面大小对齐(通常为4 KiB=4096字节)
  6. 尝试减少分支(如"if"、"for"、"while"、"()?:"等指令)并使代码线性化
  7. 如果这还不够,当情况变得艰难时:使用汇编程序(但我不建议初学者这样做)

我认为在这种情况下,多线程会适得其反,因为可以发出的文件写入有限,而且问题不容易划分为小任务,因为每个任务都需要知道它必须在其他任务之后启动多少位,然后你最终必须将所有结果连接在一起。

我过去使用过以下内容,它可能会有所帮助。。。

FileWriter.h:

#ifndef FILE_WRITER_H
#define FILE_WRITER_H
#include <stdio.h>
class FileWriter
{
public:
    FileWriter(const char* pFileName);
    virtual ~FileWriter();
    void AddBit(int iBit);
private:
    FILE* m_pFile;
    unsigned char m_iBitSeq;
    unsigned char m_iBitSeqLen;
};
#endif

FileWriter.cpp:

#include "FileWriter.h"
#include <limits.h>
FileWriter::FileWriter(const char* pFileName)
{
    m_pFile = fopen(pFileName,"wb");
    m_iBitSeq = 0;
    m_iBitSeqLen = 0;
}
FileWriter::~FileWriter()
{
    while (m_iBitSeqLen > 0)
        AddBit(0);
    fclose(m_pFile);
}
void FileWriter::AddBit(int iBit)
{
    m_iBitSeq |= iBit<<CHAR_BIT;
    m_iBitSeq >>= 1;
    m_iBitSeqLen++;
    if (m_iBitSeqLen == CHAR_BIT)
    {
        fwrite(&m_iBitSeq,1,1,m_pFile);
        m_iBitSeqLen = 0;
    }
}

您可以通过在将数据写入文件之前积累一定数量的数据来进一步改进它。