C++二进制文件读写区别 文本模式二进制模式对比

C++中文件读写文本模式与二进制模式的核心区别在于是否对数据进行字符转换:文本模式会自动转换换行符(如Windows下’n’转为”rn”),适用于人类可读的文本文件,确保跨平台兼容性;而二进制模式则直接按字节流原样读写,不作任何处理,适用于图像、音频、序列化对象等需保持字节精确性的非文本数据。选择模式的关键在于数据类型——文本用文本模式,非文本必须用二进制模式,否则可能导致文件大小错误、数据损坏或跨平台问题。通过std::ios::binary标志可显式指定二进制模式,并使用read/write函数进行安全的字节级操作,同时需注意结构体对齐、字节序和指针等问题以确保数据完整性。

c++二进制文件读写区别 文本模式二进制模式对比

C++中对文件的读写,文本模式和二进制模式的核心区别在于数据在内存与磁盘之间传输时,是否进行字符转换。文本模式会根据操作系统习惯对特定字符(如换行符)进行转换,而二进制模式则不对任何字节进行处理,直接按字节流原样读写。

解决方案

理解C++文件读写中的文本模式与二进制模式,关键在于认识到它们对字节流的处理方式截然不同。文本模式(默认模式)在读写时,会根据操作系统的约定对某些特定字符进行转换,最典型的就是换行符。在Windows系统下,一个

'n'

(LF,Line Feed)字符在写入时会被转换为

"rn"

(CRLF,Carriage Return + Line Feed),而在读取时,

"rn"

又会被转换回

'n'

。这种自动转换旨在确保跨平台文本文件的兼容性,让不同系统上的文本编辑器能正确显示换行。

然而,二进制模式则完全跳过所有这些转换。它将文件视为一个纯粹的字节序列,内存中的每一个字节都原封不动地写入文件,反之亦然。这意味着,如果你写入一个

'n'

,它在文件中就只是一个

0x0A

字节,不会被添加

0x0D

。这种“所见即所得”的特性,使得二进制模式成为处理非文本数据(如图片、音频、视频、序列化的结构体或自定义对象)的唯一正确选择。因为这些数据对每一个字节的精确性都有要求,任何意外的转换都会导致数据损坏。

简单来说,如果你处理的是人类可读的文本内容,并且需要考虑跨操作系统的换行符兼容性,用文本模式通常更省心。但只要你的数据不是纯粹的文本,或者你对文件内容的每一个字节都有精确的控制需求,那么二进制模式就是你的不二之选。

立即学习“C++免费学习笔记(深入)”;

为什么C++文件操作会有两种模式?它们各自的应用场景是什么?

C++文件操作之所以区分文本和二进制模式,其根源在于不同操作系统对“行结束”的定义存在历史差异,以及程序处理数据类型的多样性。早期的UNIX系统习惯用一个字符(

LF

,

n

)表示行结束,而DOS/Windows则沿用了CP/M的习惯,使用两个字符(

CRLF

,

rn

)。为了让在这些系统上创建的文本文件能够被对方正确识别和显示,C++标准库(以及C语言的FILE I/O)引入了文本模式,它充当了一个“翻译官”的角色。

这种设计对我来说,是历史遗留问题与实用主义的结合。它解决了文本文件的跨平台阅读难题,但同时也给不了解其内部机制的开发者埋下了坑。

各自的应用场景:

文本模式(默认)

应用场景: 读写日志文件、配置文件(如

.ini

,

.json

,

.xml

)、源代码文件(

.cpp

,

.h

,

.txt

)、CSV数据等。简单说,任何你希望用文本编辑器打开并直接阅读的文件,都适合用文本模式。优点: 自动处理换行符,简化了跨平台文本文件的兼容性问题。你在代码里写

std::endl

'n'

,它在Windows下会自动变成

rn

,读回来也自动变回

n

,对开发者来说是透明的。缺点: 无法精确控制文件中的每一个字节,对二进制数据进行读写时会导致数据损坏或意外增长。

二进制模式

应用场景: 读写图像文件(

.jpg

,

.png

,

.bmp

)、音频文件(

.mp3

,

.wav

)、视频文件、压缩文件(

.zip

,

.rar

)、可执行程序(

.exe

,

.dll

)、序列化的对象数据、数据库文件等。任何不是人类直接阅读的、需要保持原始字节精确性的数据,都必须使用二进制模式。优点: 数据按字节原样传输,不进行任何转换,保证了数据的完整性和精确性。这对于处理结构化数据、原始媒体数据等至关重要。缺点: 需要开发者自己处理所有字节细节,包括换行符(如果你的二进制数据中恰好包含

0x0A

0x0D

,它们会被原样写入,不会被特殊处理)。

在我看来,选择哪种模式,就像选择用哪种语言交流:对人说人话,对机器说机器话。对文本文件,你希望它能被不同系统的文本工具理解;对二进制文件,你只希望它能被你的程序精确地解析。

文本模式下,换行符的处理机制具体是怎样的?这会导致哪些常见问题?

文本模式下,换行符的处理机制主要是针对Windows(DOS)和Unix/Linux系统之间差异的一种“适配”。在内存中,C++标准库通常将换行符表示为单个的

'n'

(ASCII值0x0A,即Line Feed)。但在实际写入文件时,如果文件是以文本模式打开的,并且运行在Windows系统上,那么:

写入时: 每当遇到一个

'n'

字符,文件流会自动将其转换为

"rn"

(ASCII值0x0D 0x0A,即Carriage Return + Line Feed)两个字节写入文件。读取时: 每当遇到

"rn"

序列,文件流会自动将其转换回单个的

'n'

字符读入内存。单个的

'n'

'r'

则保持不变。

这种转换机制,说白了就是为了让Windows记事本之类的程序能正确显示换行。Unix/Linux系统在文本模式下通常不会进行这种转换,

'n'

就是

'n'

这会导致哪些常见问题?

文件大小计算不准确: 这是最直观的问题。如果你在Windows文本模式下写入100个

'n'

,你可能会以为文件大小增加了100字节,但实际上它增加了200字节。反之,如果你读取一个Windows创建的文本文件,文件流会自动“吞掉”

r

,导致你通过

tellg()

等函数获取的文件大小或读取的字节数与磁盘上的实际大小不符。这在需要精确计算文件内容长度或进行随机访问时尤其麻烦。

// 示例:在Windows文本模式下写入换行符#include #include void demonstrate_newline_issue() {    std::ofstream ofs("test_text.txt", std::ios::out); // 默认文本模式    if (!ofs.is_open()) {        std::cerr << "Error opening file!" << std::endl;        return;    }    ofs << "Line1" << std::endl; // std::endl 会输出 'n' 并刷新    ofs << "Line2n"; // 直接输出 'n'    ofs.close();    // 此时,test_text.txt 在Windows上实际内容是 "Line1rnLine2rn"    // 文件大小会比预期多出2个字节 (每个 n 变成 rn)    std::ifstream ifs("test_text.txt", std::ios::in);    if (!ifs.is_open()) return;    ifs.seekg(0, std::ios::end);    long long size = ifs.tellg();    std::cout << "File size (text mode read): " << size << " bytes" << std::endl;    // 注意:tellg() 在文本模式下可能返回逻辑大小,而非物理大小。    // 真正的物理大小需要通过系统API获取。    ifs.close();}

二进制数据损坏: 这是最危险的问题。如果你不小心用文本模式打开并写入了二进制数据(例如,一个图片文件,或一个序列化的结构体),而这些二进制数据中恰好包含了

0x0A

(LF)字节,那么在Windows系统上,这些

0x0A

会被自动转换为

0x0D 0x0A

。这会无声无息地在你的数据中插入额外的字节,导致文件格式被破坏,数据无法正确解析。反过来,如果你的二进制数据中包含

0x0D 0x0A

序列,读取时

0x0D

可能会被丢弃,同样导致数据不完整。

性能开销: 每次读写都需要进行额外的字符转换,这会带来一定的性能开销。对于小文件可能不明显,但对于大文件或高频I/O操作,这种开销是需要考虑的。

跨平台兼容性混淆: 虽然文本模式旨在解决跨平台问题,但有时也会引入新的混淆。比如,一个在Linux上用文本模式写入的包含

n

的文件,直接拷贝到Windows上,如果用二进制模式读取,那么

n

就是

n

;如果用文本模式读取,它仍然是

n

。但如果一个Windows上用文本模式写入的文件,拷贝到Linux上,那么它里面的

rn

就会被Linux的文本编辑器视为两个字符,显示为“^M”或者两个换行,反而不那么“兼容”了。这说明文本模式的“兼容”是有限制的,并非万能。

这些问题让我个人在使用文件I/O时,除非明确知道自己在处理纯文本且需要跨平台换行符兼容,否则我倾向于默认使用二进制模式。这样至少可以避免数据被“偷偷”修改,所有字节都由我掌控。

如何在C++中明确指定文件读写模式,并确保数据完整性?

在C++中,指定文件读写模式非常直接,通过在文件流对象的构造函数或

open()

成员函数中传入相应的

std::ios

标志即可。确保数据完整性则需要更细致的错误检查和对数据类型的正确处理。

明确指定文件读写模式:

std::ios::binary

是用于指定二进制模式的关键标志。如果省略此标志,则默认是文本模式。

文本模式(默认,或显式指定):

#include #include #include void write_text_file(const std::string& filename, const std::string& content) {    // 默认就是文本模式    std::ofstream ofs(filename);    // 或者显式指定:    // std::ofstream ofs(filename, std::ios::out | std::ios::trunc);    if (!ofs.is_open()) {        std::cerr << "Error: Could not open text file " << filename << std::endl;        return;    }    ofs << content;    ofs.close();    std::cout << "Text written to " << filename << std::endl;}void read_text_file(const std::string& filename) {    std::ifstream ifs(filename); // 默认文本模式    if (!ifs.is_open()) {        std::cerr << "Error: Could not open text file " << filename << std::endl;        return;    }    std::string line;    while (std::getline(ifs, line)) {        std::cout << "Read line (text mode): " << line << std::endl;    }    ifs.close();}

二进制模式(必须显式指定):

#include #include #include  // 用于存储字节数据// 写入二进制数据void write_binary_file(const std::string& filename, const std::vector& data) {    // 必须使用 std::ios::binary 标志    std::ofstream ofs(filename, std::ios::out | std::ios::binary | std::ios::trunc);    if (!ofs.is_open()) {        std::cerr << "Error: Could not open binary file " << filename << std::endl;        return;    }    // 使用 write 成员函数,直接写入字节块    ofs.write(data.data(), data.size());    ofs.close();    std::cout << "Binary data written to " << filename << std::endl;}// 读取二进制数据std::vector read_binary_file(const std::string& filename) {    std::vector data;    // 必须使用 std::ios::binary 标志    std::ifstream ifs(filename, std::ios::in | std::ios::binary);    if (!ifs.is_open()) {        std::cerr << "Error: Could not open binary file " << filename << std::endl;        return data; // 返回空vector    }    // 获取文件大小    ifs.seekg(0, std::ios::end);    std::streampos file_size = ifs.tellg();    ifs.seekg(0, std::ios::beg);    data.resize(file_size);    // 使用 read 成员函数,直接读取字节块    ifs.read(data.data(), file_size);    ifs.close();    std::cout << "Binary data read from " << filename << ". Size: " << data.size() << " bytes." << std::endl;    return data;}

确保数据完整性:

始终检查文件是否成功打开: 这是最基本也是最重要的一步。使用

is_open()

或检查流对象本身(它重载了

operator bool

)。

std::ofstream ofs("my_file.bin", std::ios::binary);if (!ofs) { // 或者 !ofs.is_open()    std::cerr << "Failed to open file!" << std::endl;    // 处理错误,例如退出或抛出异常    return;}

使用

read()

write()

进行二进制操作: 对于二进制数据,不要使用

<<

>>

运算符,它们是为格式化文本I/O设计的。

read()

write()

直接操作字节数组。

ofs.write(reinterpret_cast(&my_struct), sizeof(my_struct));
ifs.read(reinterpret_cast(&my_struct), sizeof(my_struct));

请注意,直接写入结构体存在对齐和字节序问题,这在不同平台或编译器之间可能导致不兼容。

处理文件结束和错误状态: 读写操作后,检查流的状态标志(

eof()

,

fail()

,

bad()

)。

eof()

: 在读取到文件末尾时返回true。

fail()

: 当操作失败(例如,读取了非数字字符到int变量)时返回true。

bad()

: 当发生严重错误(例如,硬件错误或文件损坏)时返回true。通常,在循环读取时,会这样写:

while (ifs.read(buffer, size))

while (!ifs.eof() && ifs.good()) { ... }

定位文件指针:

seekg()

(get pointer)和

seekp()

(put pointer)用于在文件中移动读写位置。

ifs.seekg(0, std::ios::beg);

// 移到文件开头

ifs.seekg(offset, std::ios::cur);

// 从当前位置偏移

ifs.seekg(0, std::ios::end);

// 移到文件末尾

std::streampos current_pos = ifs.tellg();

// 获取当前位置

刷新和关闭文件:

flush()

强制将缓冲区内容写入磁盘,

close()

关闭文件句柄并刷新缓冲区。虽然流对象析构时会自动关闭文件,但在需要确保数据立即写入或进行错误处理时,显式调用是好习惯。

在我看来,处理二进制文件时,最重要的就是“信任”:信任你写入的每一个字节都会原样出现在文件中,并且读取时也会原样返回。一旦这种信任被文本模式的“翻译”机制打破,数据完整性就岌岌可危了。所以,对二进制数据,

std::ios::binary

是强制性的。

在处理结构体或自定义对象时,二进制模式有哪些优势和潜在陷阱?

处理结构体或自定义对象时,二进制模式的优势在于其效率和直接性。你可以将对象的内存布局直接写入文件,或者从文件中直接读回内存,这通常比将其转换为文本格式(如JSON、XML)再进行读写要快得多,并且文件体积也更小。对于需要高性能I/O或存储大量复杂数据的应用来说,这无疑是巨大的吸引力。

然而,这种直接性也带来了几个潜在的陷阱,它们足以让你的程序在不同环境或版本下崩溃,或者数据变得不可读。

内存对齐(Padding)问题:C++编译器为了优化内存访问速度,可能会在结构体成员之间插入额外的字节(padding)。这意味着

sizeof(MyStruct)

可能大于其所有成员变量大小之和。当你直接将

sizeof(MyStruct)

字节写入文件时,这些填充字节也会被写入。

陷阱: 如果你在一个编译器或平台上写入,然后在另一个编译器或平台上读取,由于它们的内存对齐规则可能不同,

sizeof(MyStruct)

的值或内部布局会发生变化,导致读取的数据与预期不符,甚至覆盖到错误的内存区域。示例:

struct MyData {    char c;    int i; // 编译器可能在c和i之间插入3个字节的padding    short s; // 编译器可能在i和s之间插入2个字节的padding};// sizeof(MyData) 在某些系统上可能是 12 字节 (1 + 3 + 4 + 2 + 2), 而不是 1+4+2=7 字节// 直接 write(&data, sizeof(data)) 会写入这些填充字节

字节序(Endianness)问题:不同的处理器架构存储多字节数据(如

int

,

float

,

long long

)的字节顺序可能不同。主流的有大端序(Big-Endian,高位字节存放在低内存地址)和小端序(Little-Endian,低位字节存放在低内存地址)。

陷阱: 在小端序机器上写入一个整数

0x12345678

,它在文件中可能是

78 56 34 12

。如果你在大端序机器上直接读取这四个字节,它会被解释为

0x78563412

,而不是原始的

0x12345678

,导致数据错误。解决方案: 对于跨平台二进制文件,你需要实现自己的字节序转换函数(例如,

hton

系列函数或手动位操作),确保所有多字节数据在写入文件前都转换为统一的字节序(比如网络字节序,即大端序),读取后再转换回来。

指针和引用问题:如果你尝试直接序列化一个包含指针或引用的

以上就是C++二进制文件读写区别 文本模式二进制模式对比的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1473084.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
C++ forward_list特性 单向链表实现
上一篇 2025年12月18日 20:08:31
C++ vector容器用法 动态数组操作与优化
下一篇 2025年12月18日 20:08:53

相关推荐

  • composer require-dev和require有什么不同_Composer Require与Require-Dev区别解析

    require用于声明项目运行必需的依赖,如框架、数据库组件和第三方SDK,这些包会随项目部署到生产环境;2. require-dev用于声明仅在开发和测试阶段需要的工具,如PHPUnit、PHPStan、Faker等,不会默认部署到生产环境;3. 安装时composer install根据环境决定…

    2026年5月10日
    1000
  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    300
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 利用海象运算符简化条件赋值:Python教程与最佳实践

    本文旨在探讨Python中海象运算符(:=)在条件赋值场景下的应用。通过对比传统if/else语句与海象运算符,以及条件表达式,分析海象运算符在简化代码、提高可读性方面的优势与局限性。并通过具体示例,展示如何在列表推导式等场景下合理使用海象运算符,同时强调其潜在的复杂性及替代方案,帮助开发者更好地掌…

    2026年5月10日
    100
  • Debian syslog性能优化技巧有哪些

    提升Debian系统syslog (通常基于rsyslog)性能,关键在于精简配置和高效处理日志。以下策略能有效优化日志管理,提升系统整体性能: 精简配置,高效加载: 在rsyslog配置文件中,仅加载必要的输入、输出和解析模块。 使用全局指令设置日志级别和格式,避免不必要的处理。 自定义模板: 创…

    2026年5月10日
    000
  • 怎么在PHP代码中实现图片上传功能_PHP图片上传功能实现与安全处理教程

    首先创建含enctype的HTML表单,再用PHP接收文件,检查目录、移动临时文件,验证类型与大小,生成唯一文件名,并调整php.ini限制以确保上传成功。 如果您尝试在PHP项目中添加图片上传功能,但服务器无法正确接收或保存文件,则可能是由于表单配置、文件处理逻辑或安全限制的问题。以下是实现该功能…

    2026年5月10日
    300
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • 如何让动态追加元素的类事件生效?

    如何在追加元素后使其绑定类事件生效 在页面中引入三方 JavaScript 类并通过添加相应 class 来调用事件方法是一种常见的做法。然而,如果通过 JavaScript 追加标签元素,即使添加了对应的 class,事件也可能无法生效。 为了解决这个问题,可以尝试以下步骤: 检查追加的标签是否为…

    2026年5月10日
    000
  • Golang gRPC流式请求异常处理

    在Golang的gRPC流式通信中,必须通过context.Context处理异常。应监听上下文取消或超时,及时释放资源,设置合理超时,避免连接长时间挂起,并在goroutine中通过context控制生命周期。 在使用 Golang 和 gRPC 实现流式通信时,异常处理是确保服务健壮性的关键部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • vscode上怎么运行html_vscode上运行html步骤【指南】

    首先保存文件为.html格式,再通过浏览器或Live Server插件打开预览;推荐安装Live Server实现本地服务器运行与实时刷新,提升开发体验。 在 VS Code 上运行 HTML 文件并不需要复杂的配置,只需几个简单步骤即可预览页面效果。VS Code 本身是一个代码编辑器,不直接运行…

    2026年5月10日
    100
  • RichHandler与Rich Progress集成:解决显示冲突的教程

    在使用rich库的`richhandler`进行日志输出并同时使用`progress`组件时,可能会遇到显示错乱或溢出问题。这通常是由于为`richhandler`和`progress`分别创建了独立的`console`实例导致的。解决方案是确保日志处理器和进度条组件共享同一个`console`实例…

    2026年5月10日
    000
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • 《魔兽世界》将于6月11日开启国服回归技术测试

    《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试

    《%ign%ignore_a_1%re_a_1%》官方宣布,将于6月11日开启国服回归技术测试,时间为7天,并称可以在6月内正式开服,玩家们可以访问官网下载战网客户端并预下载“巫妖王之怒”客户端,技术测试详情见下图。 WordAi WordAI是一个AI驱动的内容重写平台 53 查看详情 以上就是《…

    2026年5月10日 用户投稿
    200
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100

发表回复

登录后才能评论
关注微信