std::ofstream 会自动在 之后添加回车符 (CR; \r)
std::ofstream is adding carriage return (CR; ) after automatically
我正在尝试在磁盘上写入PPM文件。PPM 是一种简单的图像格式,由 ASCII 图像标头和像素字节数组组成:
P6n
width heightn
255n
[width*height*3 bytes total]
这是我的PPM类(简化):
class PPMImage
{
protected:
friend std::istream& operator >>(std::istream &inputStream, PPMImage &other);
friend std::ostream& operator <<(std::ostream&, const PPMImage&);
size_t width;
size_t height;
// eg. "P6"
std::string magicNumber;
// Normally 255
uint16_t maxBrightness;
std::vector<std::vector<ImagePixel>> pixels;
};
这是我将图像写入std::ofstream
的方式:
std::ostream& operator <<(std::ostream &output, const PPMImage &other) {
// Writing header - THIS IS WHERE THE PROBLEM IS!
output<<"P6n"<<other.width<<'n'<<other.height<<'n'<<other.maxBrightness<<'n';
// The rest is pretty much irrelevant
size_t position = output.tellp();
output.seekp(position+other.width*other.height*3);
// Force the stream to be specific size
const char zero = 200;
output.write(&zero, 1);
// Write the image
output.seekp(position);
for(size_t y=0, yl=other.height; y<yl; ++y) {
for(size_t x=0, xl=other.width; x<xl; ++x) {
output.write((char*)&(other.pixels[y][x].r), 1);
output.write((char*)&(other.pixels[y][x].g), 1);
output.write((char*)&(other.pixels[y][x].b), 1);
}
}
return output;
}
这就是我如何使用这个 API:
std::ofstream out;
out.open("copy.ppm");
if(!out.is_open()) {
// error and exit here
}
out<<image;
out.close();
图像似乎还可以,除了 ofstream 在标头中的每个n
之前添加r
:
P6rn
width heightrn
255rn
[width*height*3 bytes total]
这是不可接受的。我尝试像这样更改初始化代码:
std::ofstream out("copy.ppm", std::ios::binary);
// I wonder why I have to mention "copy.ppm" twice...
out.open("copy.ppm");
但这只会创建空文件。有人可以解释如何在没有回车符的情况下正确编写 PPM wile 吗?
换句话说:如何正确初始化ofstream,使其在没有r
的情况下写入?
如果再次错误地打开文件,则会将流置于失败状态。只需调用clear()就可以工作,但这并不理想。
#include <fstream>
#include <iostream>
class CustomObject{
public:
std::string message;
explicit CustomObject(const std::string &text) : message(text) {}
friend std::ostream& operator <<(std::ostream&, const CustomObject&);
};
std::ostream& operator <<(std::ostream &output, const CustomObject &other) {
if (output.fail()){
std::cout << "the stream is in a fail state due to the bad open" << std::endl;
output.clear();
}
output << "P6n" << other.message.c_str() << 'n';
return output;
}
int main()
{
std::string filename("something.ppm");
std::ofstream out(filename, std::ios::binary);
out.open(filename);
out << CustomObject("Hello");
}
打开文件的正确方法是将所有参数(文件名和模式)传递在一起,无论您选择将其放在何处。 要么在构造函数中,要么使用开放,但不能两者兼而有之。因此,只需使用您的原始代码加上正确的Windows模式即可。
std::ofstream out;
out.open("copy.ppm", std::ios::binary);
if(!out.is_open()) {
// error and exit here
}
out<<image;
out.close();
就像你已经发现的那样,使用 std::ios::binary 是解决方案。 std::ofstream 构造函数应该打开该文件,因此删除对 out.open() 的调用。
你看到的是Windows的工件。Windows 使用rn
(又名回车/换行或0x0D 0x0A
)对来标记行尾。宇宙的其余部分只使用n
本身。这导致了疯狂的文件Windows文本模式,该模式在读取时将文件中出现的所有rn
转换为单个n
。写入时,它将所有出现的n
转换为rn
对。以std::ios::binary
模式打开文件会阻止此翻译。
std::ofstream out("copy.ppm", std::ios::binary);
// I wonder why I have to mention "copy.ppm" twice...
out.open("copy.ppm");
您不必调用打开它两次。你为什么认为你这样做?这会弄乱你的ofstream
对象,因为if the stream is already associated with a file (i.e., it is already open), calling this function fails.
[1]所以不要那样做。
- 如何正确理解回车(又名\r)?
- c++ 回车行 长字符串后跟较短的字符串
- C++控制台打印在同一行上,带回车符
- C++ 在带有回车符的终端中重新打印文本
- 点击回车按钮后不起作用
- Linux 终端:回车卡在换行处
- 排序<cr>时应最后出现与 '' 的字符串
- std::ofstream 会自动在 之后添加回车符 (CR; \r)
- 当用户输入"回车"键时停止
- cin.get() 之后的回车;C++
- boost::log 输出到 Visual Studio 输出控制台 - 为格式添加额外的 LF/CR
- 程序找不到回车符或换行符。退货超出范围
- 目瞪口呆地寻找一种有效的 c 和 c++ 方法来删除回车符(读取.csv文件)
- 无法在 Linux 上进行回车工作
- 在未格式化的文本文件中插入回车
- 在不使用空格或回车的情况下输入两个数据
- 如何使用多行回车
- OpenCV 3:可用FeatureDetector::create()和DescriptorExtractor::cr
- 正在分析具有CR LF EOL结构的.csv文件
- 使用 c++ 查找回车/换行组合