【问题标题】:C++: Store read binary file into bufferC ++:将读取的二进制文件存储到缓冲区中
【发布时间】:2014-07-12 18:53:22
【问题描述】:

我正在尝试读取二进制文件并将其存储在缓冲区中。问题是,在二进制文件中有多个以空字符结尾的字符,但它们不在末尾,而是在其他二进制文本之前,所以如果我将文本存储在 '\0' 之后,它只会将其删除缓冲区。

例子:

char * a = "this is a\0 test";
cout << a;

这只会输出:this is a

这是我的真实代码:

这个函数读取一个字符

bool CStream::Read  (int * _OutChar)
{
    if (!bInitialized)
        return false;

    int iReturn = 0;

     *_OutChar = fgetc (pFile);

    if (*_OutChar == EOF)
        return false;

    return true;
}

这就是我使用它的方式:

    char * SendData = new char[4096 + 1];

    for (i = 0; i < 4096; i++)
    {
        if (Stream.Read (&iChar))
            SendData[i] = iChar;
        else
            break;
    }

【问题讨论】:

  • 您对读取数据有什么问题吗?因为读取似乎没问题(假设打开模式是 std::binary),而且缓冲区的使用也是如此。
  • @Christophe 要打开我正在使用 fopen 并作为模式参数“ab+”的文件,我认为这是二进制文件。我接下来要做的是使用 ssl_write 将缓冲区发送到套接字,在那里我将缓冲区写回文件,但这失败了,因为接收到的缓冲区是不完整的,它只是将缓冲区写入' \0'

标签: c++ buffer fgets null-terminated


【解决方案1】:

我只想提一下,有一种从二进制文件读取到缓冲区的标准方法。

使用&lt;cstdio&gt;

char buffer[BUFFERSIZE];

FILE * filp = fopen("filename.bin", "rb"); 
int bytes_read = fread(buffer, sizeof(char), BUFFERSIZE, filp);

使用&lt;fstream&gt;

std::ifstream fin("filename.bin", ios::in | ios::binary );
fin.read(buffer, BUFFERSIZE);

当然,之后您对缓冲区的处理完全取决于您。

编辑:使用&lt;cstdio&gt;的完整示例

#include <cstdio>

const int BUFFERSIZE = 4096;    

int main() {
    const char * fname = "filename.bin";
    FILE* filp = fopen(fname, "rb" );
    if (!filp) { printf("Error: could not open file %s\n", fname); return -1; }

    char * buffer = new char[BUFFERSIZE];
    while ( (int bytes = fread(buffer, sizeof(char), BUFFERSIZE, filp)) > 0 ) {
        // Do something with the bytes, first elements of buffer.
        // For example, reversing the data and forget about it afterwards!
        for (char *beg = buffer, *end=buffer + bytes; beg < end; beg++, end-- ) {
           swap(*beg, *end);
        }
    }

    // Done and close.
    fclose(filp);

    return 0;
}

【讨论】:

  • 如果我想读取超过 1GB 的文件,我不能使用 fread,因为缓冲区太大。这是因为我正在使用 fgets,逐个字符地读取
  • @schacker22 使用 fread 而不是 fget 读取较小的缓冲区可能仍会获得更好的性能。 fread 并没有说您必须一口气阅读 整个 文件。
  • 我已经试过了,看这个:stackoverflow.com/questions/24712427/…
  • @schacker22 是的,我在那里查看了您的代码,乍一看我没有发现任何错误,除非 fseek 实际上返回错误。请注意,只要您不跳转文件,就不需要调用 fseek。
  • 文件中的当前位置存储在 FILE 对象中,因此下一次调用 fread 将继续上次读取结束的位置。 (就像 fget 一样)唯一的区别是 fread 一次读取更多的数据,因此导致的开销更少。
【解决方案2】:

问题绝对是缓冲区的写入,因为您一次读取一个字节。

如果您知道缓冲区中数据的长度,则可以强制 cout 继续:

char *bf = "Hello\0 world"; 
cout << bf << endl;
cout << string(bf, 12) << endl;

这应该给出以下输出:

Hello
Hello  world

但是这是一种解决方法,因为 cout 预计会输出可打印数据。请注意,诸如 '\0' 之类的不可打印字符的输出取决于系统。

替代解决方案:

但如果您操作二进制数据,您应该定义临时数据结构和打印。这里有一些提示,以及一般原则的快速草稿:

struct Mybuff {   // special strtucture to manage buffers of binary data
    static const int maxsz = 512; 
    int size;
    char buffer[maxsz]; 
    void set(char *src, int sz)  // binary copy of data of a given length
    { size = sz; memcpy(buffer, src, max(sz, maxsz)); }
} ; 

然后你可以重载输出操作函数:

ostream& operator<< (ostream& os, Mybuff &b)
{
    for (int i = 0; i < b.size; i++) 
        os.put(isprint(b.buffer[i]) ? b.buffer[i]:'*');  // non printables replaced with *
    return os;
}

你可以这样使用它:

char *bf = "Hello\0 world"; 
Mybuff my; 
my.set(bf, 13);   // physical copy of memory
cout << my << endl;   // special output 

【讨论】:

    【解决方案3】:
    static std::vector<unsigned char> read_binary_file (const std::string filename)
    {
        // binary mode is only for switching off newline translation
        std::ifstream file(filename, std::ios::binary);
        file.unsetf(std::ios::skipws);
    
        std::streampos file_size;
        file.seekg(0, std::ios::end);
        file_size = file.tellg();
        file.seekg(0, std::ios::beg);
    
        std::vector<unsigned char> vec;
        vec.reserve(file_size);
        vec.insert(vec.begin(),
                   std::istream_iterator<unsigned char>(file),
                   std::istream_iterator<unsigned char>());
        return (vec);
    }
    

    然后

    auto vec = read_binary_file(filename);
    auto src = (char*) new char[vec.size()];
    std::copy(vec.begin(), vec.end(), src);
    

    【讨论】:

    • 对于任何想要使用它的人: read_binary_file 函数有一行 std::vector vec(file_size);它应该只是 std::vector vec ;否则,该函数将返回一个向量,其中文件内容位于开头 x 个字节,后跟一个虚拟 x 个字节。向量有 2x 个字节!如果您想在将文件读入向量时优化内存分配,请在创建向量后立即使用 vec.reserve(file_size)。
    【解决方案4】:

    我相信您的问题不在于读取数据,而在于您尝试打​​印数据的方式。

    char * a = "this is a\0 test";
    cout << a;
    

    您向我们展示的这个示例打印了一个 C 字符串。由于 C 字符串是以 '\0' 结尾的字符序列,因此打印函数在第一个空字符处停止。 这是因为您需要通过使用特殊终止字符(如此处的“\0”)或知道字符串的长度来知道字符串的结束位置。

    因此,要打印整个数据,您必须知道它的长度,并使用类似于读取它的循环。

    【讨论】:

      【解决方案5】:

      你在 Windows 上吗?如果是这样你需要执行_setmode(_fileno(stdout), _O_BINARY);

      包括&lt;fcntl.h&gt;&lt;io.h&gt;

      【讨论】:

      • 这是fopen函数还是socket?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-05
      • 2013-05-20
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 2014-11-21
      相关资源
      最近更新 更多