第393页 '编程:Principles and Practice’ 介绍seekg()
和seekp()
如下:
但是,如果必须,可以使用定位来选择文件中的特定位置进行阅读或写入。基本上,每个打开阅读的文件都有一个“读取/获取位置”,每个打开写入的文件都有一个“写入/放置位置”:
[图解]
fstream fs {name}; // open for input and output
if (!fs) error("can't open ", name);
fs.seek(5); // move reading position to the 5 (the 6th character)
char ch;
fs >> ch; // read and increment reading position
cout << "character[5] is " << ch << ' {' << int(ch) << "}\n";
fs.seekp(1); // move writing position to 1
fs << 'y'; // write and increment writing position
在代码片段中,“位置”用字符来表示,例如位置5被称为“第6个字符”。这让我很困惑,因为在此之前,我们一直认为文件是一个字节序列,所以我希望位置可以用 bytes 表示(在上面的例子中,我认为5是文件第6个字节的位置)。
因此,我尝试通过写入包含单个宽字符的文件的位置1来测试它:
wide.txt
௸
test.cpp
#include "../std_lib_facilities.h"
int main() {
fstream fs {"wide.txt"};
fs.seekp(1);
fs << 'y';
fs.close();
return 0;
}
运行此代码后,wide.txt看起来像这样:
�y�
看起来字符'y'被写入程序的第二个字节,而不是第二个字符,这意味着位置引用的是一个字节,而不是一个字符。那么,为什么书中的代码片段说“字符”?
我还注意到函数签名是basic_ostream& seekp( pos_type pos );
(参见CPP Reference),但我找不到pos_type
是指字符还是字节的解释。
cplusplus.com上的引用似乎也是用字符来定义位置的(强调是添加的):
设置下一个字符插入输出流的位置。
就像Reddit上的comment一样(强调添加):
一个streampos不是一个整数,**它不是流中的某个字节位置。它表示流中的一个字符位置,**类型保存一些流状态信息,用于代码转换和字符位置。
但这似乎与我在示例中看到的相矛盾,其中fs.seekp(1)
似乎覆盖了字节1(第2个字节)。
2条答案
按热度按时间xqnpmsa81#
seekg()
和seekp()
是对字符还是字节进行操作?在
seek*
函数的上下文中,它们是同一个东西--它与graphemes, grapheme-like units or symbols中的可见(或不可见)字符只有非常松散的关系。对于编码,如UTF8,步进 “一个字符” 将需要澄清。
seek*
字符不考虑代码点,因此步进一个seek*
-字符可能会将r/w指针定位在4个八位字节长的unicode字符内的某个位置,并且从/向那里阅读或写入可能会导致无效的代码点-或一些意外的字素。tmb3ates2#
seekg()
和seekp()
是对字符还是字节进行操作?两个都是?
为什么书中的代码片段说“字符”?
char
是字符。它代表一个字节。在这种情况下,它们是相同的。还有
wfstream
。它对 * 宽 * 字符进行操作。这些字符采用一个wchar_t
类型编码的多个字节。pos_type是指字符还是字节。
这一切都是抽象的。这取决于流引用的内容。在
fstream
的情况下,一个字符是一个char
,它是一个字节。在wfstream
的情况下,字符具有sizeof(wchar_t)
字节。在我想象的typedef basic_ios<__uint128_t> my_super_stream_with_16_bytes_characters;
中,一个字符有16个字节。这与我在示例中看到的情况相反,其中fs.seekp(1)似乎覆盖了字节1
不,在本例中,只有
fs
* 指的是一个字符代表一个字节的流(在您的操作系统和实现上)。