'seekg()' 和 'seekp()' 是否对字符或字节进行操作?

Do `seekg()` and `seekp()` operate on characters or bytes?

提问人:user51462 提问时间:5/13/2023 最后编辑:user51462 更新时间:6/2/2023 访问量:296

问:

《编程:原理与实践》393页介绍如下: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 个字符”。这让我感到困惑,因为到目前为止,我们一直认为文件是一个字节序列,所以我希望位置用字节来表示(在上面的例子中,我认为 5 是文件第 6 个字节的位置)。

因此,我试图通过写入包含单个宽字符的文件的位置 1 来测试它:

宽 .txt

测试 .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”被写入程序的第 2 个字节,而不是第 2 个字符,这意味着该位置指的是一个字节,而不是一个字符。那么,为什么书中的代码片段会说“字符”呢?

我还注意到函数签名是(参见 CPP 参考),但我找不到引用是字符还是字节的解释。basic_ostream& seekp( pos_type pos );pos_type

cplusplus.com 的引用似乎也根据字符来定义位置(强调后加):

设置下一个字符插入输出流的位置。

Reddit 帖子上的以下评论也是如此(强调后加):

streampos 不是整数,它不是流中的某个字节位置。它表示流中的字符位置,该类型保存一些流状态信息,以便进行代码转换和字符位置。

但这似乎与我在示例中看到的内容相矛盾,其中似乎覆盖了字节 1(第 2 个字节)。fs.seekp(1)

C++ Fstream IOstream(英语:IOSTREAM)

评论

0赞 Davis Herring 5/13/2023
这在一定程度上取决于平台;你用的是哪一个?
6赞 o_oTurtle 5/13/2023
我认为“字符”在这里,而不是Unicode概念中的代码点或文本元素(即我们在屏幕上看到的内容)。char
3赞 john 5/13/2023
这很复杂,但我的理解是这是一个字符位置(也不是整数),而是一个字节偏移量。但是,具有您在测试中使用的非显式构造函数。用户需要确保以这种方式使用的任何字符位置都是有效的字符位置。就你而言,这不是真的。std::basic_ios<T>::pos_typestd::basic_ios<T>::off_typepos_typeoff_typeoff_type
2赞 john 5/13/2023
顺便说一句,返回,即字符位置。tellgtellpstd::basic_ios<T>::pos_type
1赞 john 5/14/2023
反之,整数是一个字节偏移量,字符位置由它构造。由于 1 的字节偏移量不是有效的字符位置,因此您会遇到麻烦。字符位置类型实际上称为 std::streampos。您可以对 进行算术运算,但只能使用字节偏移量,这是另一种说法,即如果不实际读取文件,您就无法知道字符在文件中的开始和结束位置。在字符由可变字节数编码的情况下,没有快捷方式。streampos

答:

0赞 Ted Lyngmo 5/13/2023 #1

对字符或字节进行操作和操作?seekg()seekp()

在函数的上下文中,它们是一回事 - 它与字素、类似字素的单位或符号中的可见(或不可见)字符只有非常松散的关系。seek*

对于像 UTF8 这样的编码,单步执行“字符”需要澄清。字符不考虑代码点,因此单步执行一个字符可能会将 r/w 指针定位在 4 个八位字节长的 unicode 字符内的某个位置,并且从那里读取或写入可能会导致无效的代码点 - 或一些意外的字素。seek*seek*

0赞 KamilCuk 5/13/2023 #2

对字符或字节进行操作和操作?seekg()seekp()

双?

为什么书中的代码片段说“字符”?

char是一个角色。它表示一个字节。在这种情况下,它们是相同的。

还有.它对字符进行操作。这些字符采用一种类型编码的多个字节。wfstreamwchar_t

pos_type是指字符还是字节。

这一切都是抽象的。这取决于流所指的内容。如果字符是一个字节。如果字符有字节。在我的想象中,一个字符有 16 个字节。fstreamcharwfstreamsizeof(wchar_t)typedef basic_ios<__uint128_t> my_super_stream_with_16_bytes_characters;

与我在示例中看到的内容相矛盾,其中 fs.seekp(1) 似乎覆盖了字节 1

不,只是在这种情况下,指的是一个字符表示一个字节的流(在您的操作系统上,在您的实现上)。fs

3赞 vitaut 6/2/2023 #3

seekg()并对代码单元进行操作,这些代码单元在 C++ 中通常被称为“字符”,尽管后一个术语非常重载并且可能意味着其他含义。它们绝对不对字节进行操作,如果您考虑到对于宽流,缓冲区元素具有 type .seekpwchar_t

引用 https://en.cppreference.com/w/cpp/io/basic_streambuf

受控字符序列(缓冲区)是一个数组,其数组始终表示子序列或关联字符序列的“窗口”。CharT