使用C从二进制文件中提取最后128个字节
我正在用C语言制作一个id3标记编辑器。我很难弄清楚如何从二进制文件末尾提取最后128个字节,以便操作/打印出id3标记所在的区域。下面是一些代码:使用C从二进制文件中提取最后128个字节,c,struct,io,id3,C,Struct,Io,Id3,我正在用C语言制作一个id3标记编辑器。我很难弄清楚如何从二进制文件末尾提取最后128个字节,以便操作/打印出id3标记所在的区域。下面是一些代码: struct Tag{ char tagMark[3]; char trackName[30]; char artistName[30]; char albumName[30]; char year[4]; char comment[30]; char genre; }; int main(
struct Tag{
char tagMark[3];
char trackName[30];
char artistName[30];
char albumName[30];
char year[4];
char comment[30];
char genre;
};
int main(int argc, char *argv[]){
struct Tag fileTag;
FILE *fp;
fp=fopen(argv[0], "r+b");
if(!fp){
printf("ERROR: File does not exist.");
}
int bufLength=129;
fseek(fp, 0, SEEK_END);
long fileLength=ftell(fp);
fseek(fp, fileLength-bufLength+1, SEEK_SET);
fread(&fileTag, sizeof(fileTag), 1, fp);
printf("%s\n", fileTag.tagMark);
return 0;
}
我正在使用一个包含正确格式的id3标记的文件来测试它。在id3标记中,前三个字节分别包含“T”、“A”和“G”,以标识标记是否存在。有人知道为什么在我运行这个程序时,“\u main”是唯一打印出来的东西吗?使用(或者如果您使用的是文件描述符而不是文件流)与文件末尾的负偏移量(-128)字节。然后读取128字节的信息
因此:
fseek(fp, -128L, SEEK_END);
lseek(fd, -128L, SEEK_END);
(有趣的是,SEEK\u END
、SEEK\u SET
和SEEK\u CUR
宏在标准C的
和POSIX的
中都有定义。)您的程序没有
fp=fopen(argv[0], "r+b");
argv[0]包含正在运行的可执行文件的名称,您需要第一个命令行参数argv[1]
。您可能会遇到的下一个问题(从ID3v2开始)是结构字段对齐,这取决于所使用的数据类型,编译器可能会在结构的连续成员之间留下“间隙”。为避免此问题,应指示编译器将字节边界上的结构与对齐(在大多数情况下,请查看编译器的文档)
这个答案清楚地解释了如果你没有使用正确的包装会发生什么
此外,请参见,在各个字段之后并不总是有终止的0,因此
printf("%s\n", fileTag.tagMark);
将打印标记,后跟歌曲标题(printf%s仅在遇到\0时停止)
IMHO,考虑到ID3是一个丛林,你最好将原始的ID3操作委托给一个现有的库,比如,并专注于编辑器的功能。你应该能够
seek(fp,-128,seek\u END)当然,这是一个很好的建议,但是在这种情况下,它仍然会从错误的文件中读取@fvu已经确定了实际问题。是的……我假设用户会检查他们是否打开了正确的文件。我忘记了基础是必要的,有时是正确文件名问题的+1。我不知道有哪种C编译器会将字符字段(如图所示的结构)按4字节的倍数对齐;在我所见过的所有编译器上,它们都是以1字节的倍数对齐的。(如果其中一个类型是int
或double
,那将是另一个问题。)@Jonathan“下一个问题”指的是ID3v2.x,OP也必须支持它才能使其程序有用,并且该类型具有多个数据类型的字段。对于给定的情况,id3v1是我唯一需要担心的版本。
printf("%s\n", fileTag.tagMark);