C++ 写入二进制mangles数据

C++ 写入二进制mangles数据,c++,io,binary,asio,C++,Io,Binary,Asio,在我的应用程序中,我从ASIO驱动程序录制音频数据: void newData(void *buffer, int length) 其中buffer是缓冲区指针,length是该缓冲区中的样本数。在我的例子中,我知道样本是4字节整数,缓冲区每次运行包含1024个样本 现在,我以两种方式保存这些示例:little endian二进制文件(稍后用作WAV文件)和文本文件。文本文件保存的字很好,我得到的数字和他们对应的样本形式的波形。但是二进制文件总是会包含一些好的数据,而其余的都被破坏了 原始数据

在我的应用程序中,我从ASIO驱动程序录制音频数据:

void newData(void *buffer, int length)
其中buffer是缓冲区指针,length是该缓冲区中的样本数。在我的例子中,我知道样本是4字节整数,缓冲区每次运行包含1024个样本

现在,我以两种方式保存这些示例:little endian二进制文件(稍后用作WAV文件)和文本文件。文本文件保存的字很好,我得到的数字和他们对应的样本形式的波形。但是二进制文件总是会包含一些好的数据,而其余的都被破坏了

原始数据(原始声音和文本保存):

损坏的数据(二进制保存):

代码(我使用
std::ofstream
):


您可以看到波浪是如何表示的,正值和负值交替出现,直到某一点。然后它就变成了垃圾。

如果我正确解释了数据中的第一行信息:

Original    binary (LE) binary (BE) binary to dec
206016      C0240300    000324C0    206016
那么正确的值就是大端数据。如果您在磁盘上看到的是0xC0240300,那么您使用的是一台小型endian机器(Intel CPU),您需要以big-endian格式写入数据(并以big-endian格式读回数据)

您目前的做法是:

//binary saving
tempOut.write((char *)buffer, length * 4);
我假设“buffer”是一个4字节整数数组(在我的工作中,它通常是一个
char
数组,但这样的转换就不相关了)

我认为“更好”的一种方法可能是:

enum { MAX_SAMPLES = 1024 };
char binbuff[4 * MAX_SAMPLES];

assert(length <= MAX_SAMPLES);
char *dst = binbuff;
for (int i = 0; i < length; i++)
{
     *dst++ = (buffer[i] >> 24) & 0xFF;
     *dst++ = (buffer[i] >> 16) & 0xFF;
     *dst++ = (buffer[i] >>  8) & 0xFF;
     *dst++ = (buffer[i] >>  0) & 0xFF;
}

tempOut.write(binbuff, 4 * length);
enum{MAX_SAMPLES=1024};
char binbuff[4*最大样本数];
断言(长度>24)&0xFF;
*dst++=(缓冲区[i]>>16)&0xFF;
*dst++=(缓冲区[i]>>8)&0xFF;
*dst++=(缓冲区[i]>>0)&0xFF;
}
tempOut.write(binbuff,4*长度);
有多个或多或少等效的机制可用于实现相同的结果

阅读将是相反的操作。将数据读入字符(字节)数组,然后将每四个字节组合成一个值:

int sample[MAX_SAMPLES];

char binbuff[4 * MAX_SAMPLES];
tempIn.read(binbuff, sizeof(binbuff));

char *src = binbuff;
for (int i = 0; i < MAX_SAMPLES; i++, src += 4)
{
     sample[i] = (src[0] & 0xFF) << 24 |
                 (src[1] & 0xFF) << 16 |
                 (src[2] & 0xFF) <<  8 |
                 (src[3] & 0xFF) <<  0;
}
int样本[MAX_样本];
char binbuff[4*最大样本数];
tempIn.read(binbuff,sizeof(binbuff));
char*src=binbuff;
对于(int i=0;i示例[i]=(src[0]&0xFF)您忘记在二进制模式下打开二进制数据的输出文件。因此,每次发送字节
0x0A
以输出时,文件都会接收(在windows系统中)
0x0D 0x0A

为什么二进制长度为*4,而文本仅为长度?@Mahmoud,因为样本是4字节整数。代码看起来不错。我认为问题出在其他地方。请检查代码中是否有错误,以便重新读取二进制文件。@Riateche我使用简单的十六进制编辑器检查二进制数据。样本也在那里被损坏。好的,请检查se show:文本输出的几行,以及二进制输出的等效十六进制值。足以看到值的差异。谢谢你的回答。这可以解释为什么会出现混乱,但我不会一直得到错误的数据,只是其中的一些。另外,用little endian保存原始字节实际上是我想要的,因为WAV文件格式指定应以little-endian格式编写示例。此外,读取不是我的问题,我使用通用十六进制编辑器读取原始二进制文件,使用Reaper显示生成的Wav文件。使代码以little-endian格式工作的更改是系统性的。如果问题是您试图在文本文件上写入二进制数据(因为您没有设置二进制标志)当然,这是一个更简单的解释。特别是在Windows上,你是否指定二进制确实很重要。我几乎为答案如此简单而感到羞愧。@JakubZaverka:答案确实在技术上很简单,但绝对不合逻辑。要向一个新程序员解释为什么我们对文件使用二进制模式,今天我们都应该这样做不必浪费神经元去记住文件的二进制模式是一种幸事(如果你能侥幸逃脱,那就是:-)。错误不在你的代码中,而是在规范中。
enum { MAX_SAMPLES = 1024 };
char binbuff[4 * MAX_SAMPLES];

assert(length <= MAX_SAMPLES);
char *dst = binbuff;
for (int i = 0; i < length; i++)
{
     *dst++ = (buffer[i] >> 24) & 0xFF;
     *dst++ = (buffer[i] >> 16) & 0xFF;
     *dst++ = (buffer[i] >>  8) & 0xFF;
     *dst++ = (buffer[i] >>  0) & 0xFF;
}

tempOut.write(binbuff, 4 * length);
int sample[MAX_SAMPLES];

char binbuff[4 * MAX_SAMPLES];
tempIn.read(binbuff, sizeof(binbuff));

char *src = binbuff;
for (int i = 0; i < MAX_SAMPLES; i++, src += 4)
{
     sample[i] = (src[0] & 0xFF) << 24 |
                 (src[1] & 0xFF) << 16 |
                 (src[2] & 0xFF) <<  8 |
                 (src[3] & 0xFF) <<  0;
}