簡體   English   中英

C++ 更有效地存儲 0 和 1,就像在二進制文件中一樣?

[英]C++ storing 0 and 1 more efficiently, like in a binary file?

我想存儲多個 arrays ,所有條目都由 0 或 1 組成。如果我按照我的方式進行操作,這個文件會非常大。 我做了一個我目前所做的極簡版本。

#include <iostream>
#include <fstream>
using namespace std;

int main(){
    ofstream File;
    File.open("test.csv");
    int array[4]={1,0,0,1};
    for(int i = 0; i < 4; ++i){
        File << array[i] << endl;   
    }
    File.close();
    return 0;
}

所以基本上有沒有辦法將它存儲在二進制文件或其他東西中,因為我的數據首先是 0 或 1? 如果是,該怎么做? 我還可以在該文件中還有換行符甚至逗號嗎? 如果后者中的任何一個都不起作用,那也沒關系。 更重要的是,如何將其存儲為只有 0 和 1 的二進制文件,所以我的文件更小。 非常感謝!

所以基本上有沒有辦法將它存儲在二進制文件或其他東西中,因為我的數據首先是 0 或 1? 如果是,該怎么做? 我還可以在該文件中還有換行符甚至逗號嗎? 如果后者中的任何一個都不起作用,那也沒關系。 更重要的是,如何將其存儲為只有 0 和 1 的二進制文件,所以我的文件更小。

顯而易見的解決方案是使用 64 個字符,例如 AZ、az、0-9 和 + 和 /,並在表中為六個條目設置每個字符代碼。 事實上,有一個稱為Base64的標准。 在 Base64 中, A編碼 0,0,0,0,0,0,而/編碼 1,1,1,1,1,1。 六個零或一的每個組合都有一個對應的字符。

這仍然會留下逗號、空格和換行符,供您用作分隔符。

如果您想盡可能緊湊地存儲數據,我建議將其存儲為二進制數據,其中二進制文件中的每一位代表一個 boolean 值。 這將允許您為您用完的每個字節的磁盤空間存儲 8 個 boolean 值。

如果你想存儲長度不是 8 的倍數的 arrays,它會變得有點復雜,因為你不能存儲部分字節,但是你可以通過在末尾存儲一個額外的元數據字節來解決這個問題指定最終數據字節有多少位有效以及有多少位只是填充的文件。

像這樣的東西:

#include <iostream>
#include <fstream>
#include <cstdint>
#include <vector>

using namespace std;

// Given an array of ints that are either 1 or 0, returns a packed-array
// of uint8_t's containing those bits as compactly as possible.
vector<uint8_t> packBits(const int * array, size_t arraySize)
{
   const size_t vectorSize = ((arraySize+7)/8)+1;  // round up, then +1 for the metadata byte

   vector<uint8_t> packedBits;
   packedBits.resize(vectorSize, 0);

   // Store 8 boolean-bits into each byte of (packedBits)
   for (size_t i=0; i<arraySize; i++)
   {
      if (array[i] != 0) packedBits[i/8] |= (1<<(i%8));
   }

   // The last byte in the array is special; it holds the number of
   // valid bits that we stored to the byte just before it.
   // That way if the number of bits we saved isn't an even multiple of 8,
   // we can use this value later on to calculate exactly how many bits we should restore
   packedBits[vectorSize-1] = arraySize%8;
   return packedBits;
}

// Given a packed-bits vector (i.e. as previously returned by packBits()),
// returns the vector-of-integers that was passed to the packBits() call.
vector<int> unpackBits(const vector<uint8_t> & packedBits)
{
   vector<int> ret;
   if (packedBits.size() < 2) return ret;

   const size_t validBitsInLastByte = packedBits[packedBits.size()-1]%8;
   const size_t numValidBits        = 8*(packedBits.size()-((validBitsInLastByte>0)?2:1)) + validBitsInLastByte;

   ret.resize(numValidBits);
   for (size_t i=0; i<numValidBits; i++)
   {
      ret[i] = (packedBits[i/8] & (1<<(i%8))) ? 1 : 0;
   }
   return ret;
}

// Returns the size of the specified file in bytes, or -1 on failure
static ssize_t getFileSize(ifstream & inFile)
{
   if (inFile.is_open() == false) return -1;

   const streampos origPos = inFile.tellg();  // record current seek-position
   inFile.seekg(0, ios::end);  // seek to the end of the file
   const ssize_t fileSize = inFile.tellg();   // record current seek-position
   inFile.seekg(origPos);  // so we won't change the file's read-position as a side effect
   return fileSize;
}

int main(){

    // Example of packing an array-of-ints into packed-bits form and saving it
    // to a binary file
    {
       const int array[]={0,0,1,1,1,1,1,0,1,0};

       // Pack the int-array into packed-bits format
       const vector<uint8_t> packedBits = packBits(array, sizeof(array)/sizeof(array[0]));

       // Write the packed-bits to a binary file
       ofstream outFile;
       outFile.open("test.bin", ios::binary);
       outFile.write(reinterpret_cast<const char *>(&packedBits[0]), packedBits.size());
       outFile.close();
    }

    // Now we'll read the binary file back in, unpack the bits to a vector<int>,
    // and print out the contents of the vector.
    {
       // open the file for reading
       ifstream inFile;
       inFile.open("test.bin", ios::binary);

       const ssize_t fileSizeBytes = getFileSize(inFile);
       if (fileSizeBytes < 0)
       {
          cerr << "Couldn't read test.bin, aborting" << endl;
          return 10;
       }

       // Read in the packed-binary data
       vector<uint8_t> packedBits;
       packedBits.resize(fileSizeBytes);
       inFile.read(reinterpret_cast<char *>(&packedBits[0]), fileSizeBytes);

       // Expand the packed-binary data back out to one-int-per-boolean
       vector<int> unpackedInts = unpackBits(packedBits);

       // Print out the int-array's contents
       cout << "Loaded-from-disk unpackedInts vector is " << unpackedInts.size() << " items long:" << endl;
       for (size_t i=0; i<unpackedInts.size(); i++) cout << unpackedInts[i] << "  ";
       cout << endl;
    }

    return 0;
}

(您可以通過在文件上運行zipgzip來使文件更緊湊:))

您確實可以寫入和讀取二進制數據。 然而,有換行符和逗號會很困難。 想象一下,您將數據保存為 boolean 數據,因此只有 1 和 0。 然后有一個逗號意味着你需要一個特殊字符,但你只有一個和零。,下一個最好的事情是制作兩個布爾值的 object,一個意味着你需要的常用數據(c++ 然后會讀取數據位對),另一個意思是你是否有逗號。 但我懷疑這是你需要的,如果你想做 csv 之類的事情,那么只需固定每列的大小就很容易(int 是 4 個字節,例如不超過 32 個字符的字符串) . 然后相應地讀寫。 假設你有你的二進制文件

要最初保存您的 object 數組說寵物,那么您將使用

FILE *apFile;
apFile = fopen(FILENAME,"w+");
fwrite(ARRAY_OF_PETS, sizeof(Pet),SIZE_OF_ARRAY, apFile);
fclose(apFile);

要訪問您的idx寵物,您可以使用

Pet m;
ifstream input_file (FILENAME, ios::in|ios::binary|ios::ate);
input_file.seekg (sizeof(Pet) * idx, ios::beg);
input_file.read((char*) &m,sizeof(Pet));
input_file.close();

還可以在末尾添加數據,在中間更改數據等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM