C++基础-文件读取fread和文件指针和内存查看和_Placeholder
这里使用Visual Studio来写C++代码,使用UltraEdit来查看二进制文件。(用Visual Studio也能以二进制形式打开文件,能满足大部分需求了,只是无法打开大文件,实测无法打开这里的300M的yuv文件)
下面的代码从yuv文件中读取一帧Y分量并保存起来。
#include int main()
{FILE* file_in;fopen_s(&file_in, "C:\\Users\\vid\\Documents\\Working\\BasketballDrillText_832x480_50.yuv", "rb");const int width = 832;const int height = 480;int image_size = width * height; // == 339 360 == 0x61800//使用fread读取一帧视频的Y分量unsigned char* in = new unsigned char[image_size];if (!file_in){std::cout << "Error: Read input file failed.";return 1;}else{//fread(in, 1, 1, file_in);//fread(in, 1, 1, file_in);//fread(in, 1, 1, file_in);fread(in, 1, image_size, file_in);}//把读到这第1帧图片存起来FILE* file_out;fopen_s(&file_out, "out_BasketballDrillText_832x480_y_1.yuv", "wb");if (!file_out){std::cout << "Error: Write output average file failed.";return 1;}else{fwrite(in, 1, image_size, file_out);}fclose(file_out);//保存这第1帧图片,如果我不想麻烦地先fread再fwrite呢?直接对着file_in指针使用fwrite可以吗?可以,但是//注意,在fread读了1帧以后,文件指针file_in移动到了第1帧末尾,这里如果直接试图保存文件的话,保存的就不是第1帧的Y分量,而是第1帧的U和V,再加上第2帧的一部分Y分量。//这样不规范,或者不对,不进行fread不能读文件的,写入的应该是混乱。//FILE* file_out;fopen_s(&file_out, "out_BasketballDrillText_832x480_y_2.yuv", "wb");if (!file_out){std::cout << "Error: Write output origin file failed.";return 1;}else{fwrite(file_in, 1, image_size, file_out);}fclose(file_out);fclose(file_in);delete[] in;return 0;
}
运行结果:
第1次fwrite保存的图片正常。(可以用雷神的yuv播放器打开,记得切换显示Y模式)

第2次fwrite保存的图片不太正常。(怀疑图片上方的混乱的应该是第1帧的U和V分量)

为什么会这样?编译器温馨地警告了第2次的fwrite写法是不太正确的:

直接把输入文件指针file_in放到fwrite里来保存文件是不行的,应该先fread再fwrite。
(虽然这里竟然可以读出一张像模像样的图出来,可能是因为fread第1帧时,系统多读了一些储备着,所以继续调用fwrite能出个图。不过我多次运行,发现每次读出来的图都有一些差别,也就是说这一块读出来的是有点混乱的,不能保证正确的。)
我们试试不fread直接fwrite:
#include int main()
{FILE* file_in;fopen_s(&file_in, "C:\\Users\\vid\\Documents\\Working\\BasketballDrillText_832x480_50.yuv", "rb");const int width = 832;const int height = 480;int image_size = width * height; // == 339 360if (!file_in){std::cout << "Error: Read input file failed.";return 1;}FILE* file_out;fopen_s(&file_out, "out_BasketballDrillText_832x480_y_2.yuv", "wb");if (!file_out){std::cout << "Error: Write output origin file failed.";return 1;}else{fwrite(file_in, 1, image_size, file_out);}fclose(file_out);fclose(file_in);return 0;
}
这样fwrite出来的文件是空的。
如果不调用fread函数,file_in文件指针的_Placeholder一直是0,如下图。所以这时试着把file_in用fwrite写入文件,当然得到的是不正确的。VS在这方面给的提醒是一个警告,不是一个报错。


在内存里究竟是什么样子的呢??
VS在调试时,调试 - 窗口 - 内存,打开内存窗口(快捷键:先按 Ctrl Alt M ,后 1 )。
可以F10单步调试,查看局部变量窗口中file_in变量的变化。
执行完第一句 File* file_in;,定义文件指针file_in:

执行fopen_s(&file_in, "**.yuv", "rb");,把文件指针指向文件:

执行fread(in, 1, 1, file_in);,读入一个字节:

通过把file_in的值输入到内存窗口的地址上,可以看到file_in是_Placeholder的指针(地址)

可以看出这里是小段存储,即0x00a91191的低位先存储(放在低字节)。那去指针_Placeholder指向的地址0x00a91191看一下:(这里地址故意-1方便对比)

可以看到和yuv文件的内容是一致的:(下图是UltraEdit打开YUV文件查看其内容)

fread(in, 1, 1, file_in);每读1字节,_Placeholder就会+1,file_in没变。_Placeholder指向的是内存中存储读到的文件的位置(大概是缓冲区?),是最最实在的文件指针,file_in是指针_Placeholder的指针。如果内存窗口往下翻一翻,会发现内存窗口后面是空白了(都是??或者00之类的),就是说系统实际上只读了一点点文件,所以fread是有用的,系统内存里准备好的只比fread写的稍微多一点。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
