ifstream::read 不读取无符号字符,即使使用 reinterpret_cast
Posted
技术标签:
【中文标题】ifstream::read 不读取无符号字符,即使使用 reinterpret_cast【英文标题】:ifstream::read not reading unsigned char, even with reinterpret_cast 【发布时间】:2016-10-30 23:49:26 【问题描述】:我正在尝试让我的代码读取 PPM 图像 (P3),但它无法正常工作。这个想法是获取 3 个无符号字符并将它们存储在 RGB 中。但目前它只会导致获取第一个字符而忽略其余字符。
Image Image::readImg(std::string const &filename)
std::ifstream ifs;
ifs.open(filename.c_str(), std::ios::binary);
Image _in;
try
if (ifs.fail())
throw("Can't open input file");
std::string header;
int w, h, max;
ifs >> header;
if (strcmp(header.c_str(), "P3") != 0) throw("Can't read input file");
ifs >> w >> h >> max;
_in.init(w, h);
ifs.ignore(256, '\n');
unsigned char pix[3];
for (int i = 0; i < h; ++i)
for (int j = 0; j < w; ++j)
ifs.read(reinterpret_cast<char *>(pix), 3);
_in.pixels[i][j].R = pix[0];
_in.pixels[i][j].G = pix[1];
_in.pixels[i][j].B = pix[2];
std::cout << "|" << _in.pixels[0][0].R << " " << _in.pixels[0][0].G << " " << _in.pixels[0][0].B << "|";
ifs.close();
catch (const char *err)
fprintf(stderr, "%s\n", err);
ifs.close();
return _in;
注意 std::cout 应该在我的场景 |186 0 255| 中输出,但我得到的是 |1 8 6|。
编辑: 文件(original.ppm)在 Notepad++ 中打开时如下所示(UNIX / UTF-8):
P3
1024 768
255
186 0 255 186 0 255 186 0 255 186 0 255 186 0 255 186 0 255 186 1 255
186 1 254 186 1 254 185 2 254 185 2 254 185 1 254 185 2 253 185 3 253
185 2 252 185 3 252 185 3 252 185 3 252 185 3 251 184 4 251 184 4 251
184 4 251 184 4 251 184 5 250 184 5 250 183 5 250 183 6 249 183 6 249
183 6 249 183 6 248 183 7 249 183 7 249 183 7 248 183 7 247 183 8 247
182 7 247 182 8 246 183 9 247 183 9 246 183 9 246 182 9 246 181 9 246
182 9 246 181 10 245 182 10 245 181 10 244 181 10 245 181 11 244 181 11 244
...
结果应该是: _in.pixels[0][0].R = 186 _in.pixels[0][0].G = 0 _in.pixels[0][0].B = 255 并继续收集文件中所有像素的RGB。
【问题讨论】:
operator>>
用于读取空格分隔的文本。除非P3
后跟一个空格,否则在文件中,这是行不通的。
这不是问题,但不要对控制流使用异常。您不需要关闭文件;析构函数会这样做。因此,当您检测到错误时,打印消息并返回。
"请注意 std::cout 应该在我的场景 |186 0 255| 中输出,但我得到的是 |1 8 6|。"我从中推断出您的输入是文本格式的-这意味着组件不是编码为二进制字节,而是以十进制写入的这些字节的文本表示形式。然而,您尝试在 ifs.read(..., 3)
和接下来的 3 个 assgns 中将它们读取为 3 个字节。
P3 PPM 是一种文本格式。你得到了相同数字的 3 位数字,因为在这些位置有 3 个文本字符 186
。
如何在每个像素循环中准确读取 3 个值并以某种方式组织它以获得 RGB?请注意,这些应该代表字节。
【参考方案1】:
[更新]这应该可以工作:
int pix[3]; // not an unsigned char
...
ifs >> pix[0] >> pix[1] >> pix[2];
代替:
ifs.read(reinterpret_cast<char *>(pix), 3);
就像你对宽度和高度所做的那样?
ifs >> w >> h >> max;
【讨论】:
还是同样的问题。它确定 1 8 和 6 在它们应该是一个有凝聚力的无符号字符时都是单独的字符。 您的_in.pixels[i][j].R
也是字符?如果是这样,请使用 temp int / uint 值来读取。我已经用它更新了答案。
输出只是乱七八糟的符号。
让我猜猜... �� ?您是否在调试器中检查了值是什么?当然,如果 char 值是,例如65 你会在输出中得到 beatufill 'A' 字母,而对于 186 和 255,你会得到一些“乱码”......
啊哈,它确实有效。在 UTF-8 中,notepad++ 标识正在获取的值并将其存储为 8 位字符。因此 186 在转换时显示为“xBA”或 186。谢谢 :) 现在我只需要弄清楚如何操作它并输出转换后的值。【参考方案2】:
在流中使用 >> 操作默认会跳过空格。
如果您想保留所有字符,请执行(在读取之前):
ifs >> std::noskipws;
您可能还需要以二进制模式打开文件。但我认为没有必要。
如果你想将两个字节准确地读入一个字符串,你可以使用它来代替 getline:
std::string st;
st.resize(2);
ifs.read(&st[0], st.size());
【讨论】:
做了第一位,考虑到文件的布局方式,这不是问题(参见 OP 中的新编辑)。已经处于二进制模式。和 std::string st(2);无法正确编译。 使用 std::string st ; st.resize(2); 字符串调整大小,看起来它只调整字符串中字符的大小,因此通过执行上述操作,它将读取 st[0] = 1 和 st[1] = 8。这将不工作。 这是一个如何读取两个字节的示例(如在标题中)。如果你想读取三个字节,那就把它改成三个。 我已经这样做了,只是没有提及。 st[0] = 1,st[1] = 8 和 st[2] = 6以上是关于ifstream::read 不读取无符号字符,即使使用 reinterpret_cast的主要内容,如果未能解决你的问题,请参考以下文章