电子商务网站建设的基本要素,免费seo关键词优化服务,合肥企业网站,做社群最好的网站源码1 流和缓冲区
C中#xff0c;流#xff08; stream #xff09;和缓冲区#xff08; buffer #xff09;是两个紧密相关的概念#xff0c;它们在处理输入和输出时起着重要的作用。 流#xff08; Stream #xff09; 流是一种抽象的概念#xff0c;用于表示数据的流动…1 流和缓冲区
C中流 stream 和缓冲区 buffer 是两个紧密相关的概念它们在处理输入和输出时起着重要的作用。 流 Stream 流是一种抽象的概念用于表示数据的流动。在 C 中流是一个类对象它封装了与输入/输出设备如键盘、显示器、文件等的交互。C标准库提供了多种流类如 std::cin 标准输入流通常用于从键盘读取数据、 std::cout 标准输出流通常用于向显示器输出数据以及 std::fstream 文件流用于文件的读写。 缓冲区 Buffer 缓冲区是一个用于临时存储数据的内存区域。当使用流进行输入或输出时数据通常不会直接发送到设备或从设备读取而是首先存储在缓冲区中。缓冲区的使用可以提高输入/输出的效率因为它允许程序以块的形式处理数据而不是一个字符一个字符地处理。 对于输出流程序首先将数据写入缓冲区然后当缓冲区满或程序显式地刷新缓冲区时数据才会被发送到输出设备。对于输入流程序从缓冲区读取数据当缓冲区为空时流会从输入设备读取更多的数据填充缓冲区。 缓冲区的类型 C中的流缓冲区主要有三种类型 1全缓冲当缓冲区满时缓冲区的数据才会被发送。这种方式适用于大量数据的输入/输出。 2行缓冲当遇到换行符时缓冲区的数据才会被发送。这种方式通常用于终端设备如键盘和显示器。 3不带缓冲数据立即被发送不经过缓冲区。这种方式通常用于错误报告和紧急情况。 iostream 文件 C 中的 iostream 文件中包含了一些用来实现管理流和缓冲区的类。iostream 中的 io 是 “input/output” 的缩写而 stream 表示流即数据流动的通道。 在 iostream 库中主要包含了以下几个组件 1缓冲区 streambuf 类 streambuf 类为流提供了一个缓冲区这个缓冲区用于暂存输入/输出的数据从而允许更高效的I/O操作。streambuf 是一个抽象基类不能直接实例化。它的实现如 filebuf 、 stringbuf 等会作为其他流类如 ifstream 、 ofstream 、 istringstream 、 ostringstream 等的成员被使用。 2输入流 istream 类用于从输入设备如键盘读取数据。 3输出流 ostream 类用于向输出设备如显示器写入数据。 4输入输出流 iostream 类从 istream 和 ostream 继承了输入和输出的方法多重继承既可以读取数据也可以写入数据。 5流对象如 std::cin标准输入流通常用于从键盘读取数据、std::cout标准输出流通常用于向显示器输出数据、std::cerr用于输出错误消息和 std::clog用于输出日志消息。 6操纵器 manipulators这些是用来控制流的状态或格式的函数例如 std::endl、std::flush、std::setprecision 等。 7流提取运算符 用于从输入流中读取数据。 8流插入运算符 用于向输出流中写入数据。 重定向 可以使用 C 标准库函数 freopen 函数来重定向标准输入流 std::cin 或标准输出流 std::cout 到文件或其他流。当重定向一个流时实际上是改变了流与底层设备如文件或控制台的关联。例如可以将 std::cin 重定向到一个文件这样当从 std::cin 读取时实际上是从文件中读取数据。如下为样例代码
#include iostream
#include fstream using namespace std;int main() {// 重定向 std::cin 到一个输入文件在这个文件中输入 1 并保存freopen(input.txt, r, stdin);// 重定向 std::cout 到一个输出文件 freopen(output.txt, w, stdout);int val;cout get a number from input.txt : ; // cout 写入到 output.txt cin val; // 实际上从 input.txt 读取 cout val endl; // cout 写入到 output.txt // 关闭重定向 //freopen(NULL, r, stdin); // 重置 std::cin 到标准输入 //freopen(NULL, w, stdout); // 重置 std::cout 到标准输出 return 0;
}执行完这段代码后output.txt 被存入字符串“get a number from input.txt : 1” 。 在上面代码中freopen 函数将 std::cin 重定向到名为 input.txt 的文件用于读取将 std::cout 重定向到名为 output.txt 的文件用于写入。因此当从 std::cin 读取时实际上是在读取 input.txt 文件的内容而当向 std::cout 写入时数据会被写入到 output.txt 文件中。 注意重定向流可能会影响程序的其他部分因为它改变了流的默认行为。因此在重定向流之后务必小心处理输入和输出以避免意外的行为或错误。 另外如果想要在执行完一些重定向操作之后恢复流的原始状态可以使用 freopen 函数将流重新关联到其原始设备比如将第一个参数设置为 NULL 即可将输入与输出定向为标准输入与输出。
2 输出
输出流 output stream 是 I/O 流库中的一个关键概念它允许程序将数据发送到特定的目的地如控制台、文件或其他类型的设备。C 标准库中的 ostream 类是输出流的基础。
2.1 std::cout 的基本使用
std::cout 是 C 中最常用的输出流对象它通常与控制台或终端相关联用于向用户显示信息。可以使用插入运算符 向 std::cout 发送数据该运算符将数据发送到输出流中。 。如下为样例代码
#include iostream
#include string using namespace std;int main() {int val1 1;double val2 1.21;char val3 a;string val4 hello;std::cout int val1 val1 std::endl;std::cout double val2 val2 std::endl;std::cout char val3 val3 std::endl;std::cout string val4 val4 std::endl;return 0;
}上面代码的输出为
int val1 1
double val2 1.21
char val3 a
string val4 hello除了 std::cout C 标准库还提供了其他一些输出流对象例如 std::cerr用于输出错误消息。与 std::cout 不同的是std::cerr 通常不会被缓冲因此它用于需要立即显示的错误或诊断信息。 std::clog用于输出日志消息。与 std::cerr 类似但它通常会被缓冲。 std::wcout与 std::cout 类似但用于输出宽字符wchar_t 类型。 std::wcerr 和 std::wclog与 std::cerr 和 std::clog 类似但用于输出宽字符。 此外还可以创建自定义的输出流通过继承 std::ostream 类并重载插入运算符来实现。这允许控制数据如何被发送到特定的目的地例如写入到特定的文件或进行特定的格式化处理。 在处理输出流时还可以使用操纵器 manipulators 来更改流的状态或格式。例如std::endl 操纵器不仅插入一个新行还刷新输出缓冲区确保所有数据都被发送到其目标。 std::flush 操纵器也可以用来刷新输出缓冲区。
2.2 std::cout 的格式化
std::cout 可以使用各种格式化标志和操纵器manipulators来控制输出的格式。以下是一些常见的格式化选项 1整数输出 1.1十进制
int val 12;
std::cout val std::endl;// 输出 121.2十六进制
int val 12;
std::cout std::hex val std::endl;// 输出 c1.3八进制
int val 12;
std::cout std::oct val std::endl;// 输出 141.4二进制 std::cout 默认不直接支持二进制数据的输出。如果想要输出一个整数的二进制表示则要手动将整数转换为二进制字符串然后再使用 std::cout 输出这个字符串。
#include iostream
#include bitset void printBinary(int val) {// std::bitset 可以将整数转换为二进制字符串 std::bitset32 binaryVal(val); // 4 个字节共 32 位 // 输出二进制字符串 std::cout binaryVal std::endl;
}int main() {int val 12;printBinary(val); // 输出 num 的二进制表示 return 0;
}上面代码输出为
000000000000000000000000000011002浮点数输出 2.1固定点表示法 默认情况下std::cout 使用科学记数法来输出非常大或非常小的浮点数。使用 std::fixed 使浮点数总是以固定的小数位数显示。
double pi 3.141592653589793;// 不使用 std::fixed默认输出可能使用科学记数法
std::cout default output: pi std::endl;// 使用 std::fixed 以小数位数显示
std::cout std::fixed fixed output: pi std::endl;2.2固定点表示法 默认情况下std::cout 使用科学记数法来输出非常大或非常小的浮点数。使用 std::fixed 使浮点数总是以固定的小数位数显示。
double pi 3.141592653589793;
std::cout std::scientific pi std::endl;// 输出 3.141593e002.2设置精度 设置精度使用接口 std::setprecision 注意该接口需要引用头文件 #include
double pi 3.141592653589793;
std::cout std::setprecision(3) pi std::endl;// 输出 3.143字符串输出
std::cout Hello, World! std::endl;// 输出 Hello, World!std::string str Hello, World!;
std::cout str std::endl;// 输出 Hello, World!4布尔值输出 布尔值默认以整数形式显示 true为 1 false 为 0 。可以通过 std::boolalpha 来改变这一点使 true 和 false 以文字形式显示。
bool flag true;
std::cout flag std::endl; // 输出 1std::cout std::boolalpha flag std::endl;// 输出 true5设置填充和宽度 使用 std::setw 操纵器可以设置下一个输出字段的宽度。如果输出数据小于这个宽度std::cout 会在数据前面或后面填充空格直到达到指定的宽度。此外还可以使用 std::setfill 操纵器来设置填充字符。
int val 123;
std::cout std::setw(5) std::setfill(0) val std::endl; // 输出 001236设置左对齐和右对齐 使用std::left或std::right来控制输出的对齐方式。
#include iostream
#include iomanipint main() {std::cout std::left std::setw(10) Hello std::endl; // 左对齐 std::cout std::right std::setw(10) Hello std::endl; // 右对齐return 0;
} 上面代码输出为
HelloHello2.3 多线程中应用 std::cout
C 中std::cout 并不是线程安全的。这意味着如果从多个线程同时写入 std::cout可能会遇到数据竞争data race的问题这会导致未定义的行为程序可能会崩溃或者无响应。 可以使用互斥锁如 std::mutex 来保护对 std::cout 的访问。每个线程在写入 std::cout 之前必须获取锁并在写入完成后释放锁。这样可以确保每次只有一个线程可以访问 std::cout。如下为样例代码
#include iostream
#include thread
#include mutex std::mutex g_coutMutex; // 全局互斥锁 void safePrint(const std::string message) {std::lock_guardstd::mutex lock(g_coutMutex); // std::lock_guard是一个方便的RAII包装器它会在构造时锁定互斥锁并在析构时解锁。这使得代码更加简洁并减少了出错的可能性。std::cout message std::endl;
}int main() {std::thread t1(safePrint, Hello from thread 1);std::thread t2(safePrint, Hello from thread 2);t1.join();t2.join();return 0;
}2.4 printf
printf 是 C 语言标准库中的一个函数用于格式化输出到标准输出流通常是终端或控制台窗口。它接受一个格式字符串和与之对应的值作为参数然后根据格式字符串中的说明符将值打印出来。 printf 函数是线程安全的所以在 C 的多线程开发中比 std::cout 用的更方便一些。 ** printf 常用的格式说明符及其含义** %d 或 %i带符号十进制整数。 %u无符号十进制整数。 %f浮点数默认保留小数点后六位。 %c字符。 %s字符串。 %p指针地址。 %x 或 %X无符号十六进制整数小写或大写。 %o无符号八进制整数。 %%输出一个 % 字符。 除了转换说明符格式字符串还可以包含以下可选的标志、宽度、精度和长度修饰符 标志 -左对齐输出。 在正数前面显示符号。 空格在正数前面显示空格。 #对于 f、e、E、g、G输出小数点对于 o输出前导零对于 x 或 X输出 0x 或 0X 前缀。 0用零填充空白处。 精度 对于整数d、i、o、u、x、X指定最小数字个数。 对于浮点数e、E、f、g、G指定小数点后的数字个数。 对于字符串s指定最大字符数。 长度修饰符 h指定短整型short或单字符char。 l指定长整型long。 ll指定长长整型long long。 L指定宽字符或宽字符串。 j指定 intmax_t 类型。 z指定 size_t 类型。 t指定 ptrdiff_t 类型。
3 输入
C 的输入流Input Stream通常指的是从某个数据源如键盘、文件等读取数据的流。C标准库中的 头文件提供了基本的输入流功能主要通过 std::istream 类及其派生类 std::cin 来实现。 std::cin是预定义的对象代表从标准输入通常是键盘接收数据的输入流。可以使用 运算符从std::cin读取数据这些数据会被存储在相应的变量中。 如下为样例代码使用 std::cin 从键盘读取数据
#include iostream int main() { int val; std::cout input an integer : ; std::cin val; // 从标准输入读取整数并存储在变量 val 中 std::cout the input integer is: val std::endl; return 0;
}4 文件操作
C 的文件操作主要涉及文件的打开、关闭、读取和写入。C标准库中的 头文件提供了用于文件操作的类其中 std::ifstream 用于读取文件 std::ofstream 用于写入文件而 std::fstream 则既可以读取也可以写入文件。 打开文件 在读取或写入文件之前需要使用相应的文件流对象打开一个文件。可以通过提供文件名来构造一个文件流对象该对象会在构造时尝试打开文件。如下为样例代码
#include fstream
#include iostream int main() {// 创建一个用于写入的文件流对象 std::ofstream outfile(test.txt);// 检查文件是否成功打开 if (!outfile) {std::cerr failed to open the file std::endl;return 1;}// 写入一些数据到文件 outfile hello std::endl;// 关闭文件 outfile.close();return 0;
}读取文件 使用 std::ifstream 可以读取文件的内容。可以使用流提取运算符 或 getline 函数来读取数据。如下为样例代码
#include fstream
#include iostream
#include string int main() {// 创建一个用于读取的文件流对象 std::ifstream infile(test.txt);// 检查文件是否成功打开 if (!infile) {std::cerr failed to open the file std::endl;return 1;}// 读取文件内容 std::string line;while (std::getline(infile, line)) {std::cout line std::endl;}// 关闭文件 infile.close();return 0;
}快速读取大文件 如果需要快速读取一个大文件则要避免逐行读取或者逐字符读取带来的额外开销。一种快速读取文件的方法是使用文件流的 read 成员函数它可以一次读取多个字符这样可以减少系统调用的次数从而提高读取效率。如下为样例代码
#include fstream
#include iostream
#include vector int main() {// 打开文件 std::ifstream file(large_file.bin, std::ios::binary);// 检查文件是否成功打开 if (!file){std::cerr failed to open the file std::endl;return 1;}// 获取文件大小 file.seekg(0, std::ios::end);std::streamsize fileSize file.tellg();file.seekg(0, std::ios::beg);// 分配足够的内存来存储文件内容 std::vectorchar buffer(fileSize);// 读取文件内容到buffer if (!file.read(buffer.data(), fileSize)) {std::cerr 读取文件失败 std::endl;return 1;}// 在这里处理文件内容例如可以将其输出到标准输出 std::cout.write(buffer.data(), fileSize);// 关闭文件 file.close();return 0;
}读写文件 下面是一个同时包含读取和写入操作的示例
#include fstream
#include iostream
#include string int main() {// 写入文件 std::ofstream outfile(test.txt);if (!outfile){std::cerr failed to open the file std::endl;return 1;}outfile first line std::endl; //写入第一行outfile second line std::endl; //写入第二行outfile.close();// 读取文件 std::ifstream infile(test.txt);if (!infile) {std::cerr failed to open the file std::endl;return 1;}std::string line;while (std::getline(infile, line)){std::cout line std::endl;}infile.close();return 0;
}文件流的状态 可以使用文件流对象的 is_open() 成员函数来检查文件是否已成功打开。此外还可以使用 fail() , eof() , 和 bad() 等成员函数来检查流的状态。 文件流的其他操作 clear(): 重置流的状态标志。 seekg() 和 seekp(): 移动文件的读写指针。 tellg() 和 tellp(): 返回文件的读写指针当前位置。 flush(): 清空输出缓冲区确保所有数据都被写入文件。