我必须将数值数据写入二进制文件。由于我处理的一些数据向量可以是几个演出,我已经学会了不使用C ++ iostream。相反,我想使用C File *。我正在遇到一个问题,我需要在二进制文件的前面写一些元数据。由于一些元数据一开始就不知道,所以当我将元数据添加到文件中的相应偏移量时,我需要附加元数据。
例如,假设我必须输入年,月和日的uint16_t表示,但首先我需要跳过第一个条目(uint32_t值表示精度);
我不知道我做错了什么,但我似乎无法用“ab”附加文件。 这是我写的一个例子:
#include<cstdio>
uint16_t year = 2001;
uint16_t month = 8;
uint16_t day = 23;
uint16_t dateArray[]={year , month, day};
File * fileStream;
fileStream = fopen("/Users/mmmmmm/Desktop/test.bin" , "wb");
if(fileStream){
// skip the first 4 bytes
fseek ( fileStream , 4 , SEEK_SET );
fwrite(dateArray, sizeof(dateArray[0]) ,( sizeof(dateArray) / sizeof(dateArray[0]) ), filestream);
fclose(filestream);
}
// loops and other code to prepare and gather other parameters
//现在以精确度附加文件的前面。
uint32_t precision = 32;
File *fileStream2;
fileStream2 = fopen("/Users/mmmmmm/Desktop/test.bin" , "ab");
if(fileStream2){
// Get to the top of the file
rewind(fileStream2);
fwrite(&precision, sizeof(precision) , 1 , fileStream2);
fclose(fileStream2);
}
附加数据不会写入。如果我将其更改为“wb”,则文件将被覆盖。我能够让它与“r + b”一起工作,但我不明白为什么。我认为“ab”是合适的。另外,我应该使用缓冲区还是一种充分的方法?
感谢您的建议
BTW这是在MacOSX上
答案 0 :(得分:3)
由于硬盘驱动器和文件系统的工作方式,将字节插入文件中间的速度非常慢,应该避免,尤其是在处理数GB的文件时。如果您的元数据存储在固定大小的标头中,只需确保在开始使用其他数据之前有足够的空间。如果标题的大小可变,则将标题组合起来。在开头放置1k标头空间,并保留8个字节以包含到下一个标头块的偏移值,或者对于EOF包含0。然后,当该块被填满时,只需将另一个块添加到文件的末尾,并将其偏移量写入前一个头。
对于技术IO,请根据您的需要使用fopen()
,r+b
或w+b
的{{1}}模式。它们的行为都是微不足道的。 a+b
从第一个字节开始打开文件进行读写。如果文件不存在,则会出错。 r+b
也会这样做,但如果文件不存在,则创建该文件。 w+b
与a+b
相同,但它以文件末尾的文件指针开头。
您可以使用r+b
和fseek()
导航文件。 rewind()
将文件指针移回文件的开头。 rewind()
将文件指针移动到指定位置。您可以阅读更多相关信息here.
答案 1 :(得分:1)
“r + b”表示您可以读取和写入文件中的任何位置。在第二个代码块中,rewind()调用将当前位置设置为字节0,并在此位置完成写入。
如果使用“a + b”,这也意味着读写访问,但写入都在文件末尾,因此除非创建新的空文件,否则无法定位到字节0。
要在特定字节重新访问该文件,只需使用fseek()。
fseek(fileStream,0,SEEK_SET); - 位置精确值
fseek(fileStream,4,SEEK_SET); - 年份值的位置
fseek(fileStream,8,SEEK_SET); - 月份值的位置
fseek(fileStream,12,SEEK_SET); - 日期值的位置
答案 2 :(得分:0)
使用如此大的文件,仅在几个字节之前重写演出是非常低效率的。
最好为每个文件创建一个小的伴随文件,其中包含每个文件所需的元数据,并且仅将元数据字段添加到文件的开头,以便无论如何都要在编辑时对其进行重写。
这是因为在大多数文件系统上,前置文件非常昂贵。 NTFS为大多数文件提供了第二个数据通道,几乎所有程序都看不到它,除了MS内部文件(例如文件管理器和安全扫描程序)。您可以轻松地编写一个程序以将元数据添加到该通道,而无需每次都覆盖磁盘上的演出。