IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++在终端、文件中就地覆盖输出的方法 -> 正文阅读

[C++知识库]C++在终端、文件中就地覆盖输出的方法

1、在终端就地覆盖输出字符

先上效果图,如图1-1所示:
在这里插入图片描述

图1-1


对应的程序如下:

#include <iostream>
#include <unistd.h>

int main(int argc, char* argv[])
{
    // 设置为无缓冲
    setbuf(stdout, NULL);
    // 隐藏光标
    std::cout << "\033[?25l";

    for (int i = 1; i <= 10; i++)
    {
        std::cout << i << "\r";
        sleep(1);
    }

    // 输出换行并恢复光标(光标不见了可以在终端执行 echo -e "\033[?25h" 就可以了)
    std::cout << std::endl << "\033[?25h";
}

这个程序存在着一定的问题,如果是倒计时的话效果如图1-2所示:

在这里插入图片描述

图1-2


可以看到一开始输出了10,占两个字符位置,后面由于都是输出单字符的数字,所以10后面的那个0一直停留在那里独自抱窝。对程序进行完善修改如下:

#include <iostream>
#include <unistd.h>

int count_bit(int number)
{
    int count = 1;
    while (number /= 10)
    {
        count++;
    }
    return count;
}

int main(int argc, char* argv[])
{
    // 设置为无缓冲
    setbuf(stdout, NULL);
    // 隐藏光标
    std::cout << "\033[?25l";

    int last_bit = 0;
#if 1
    for (int i = 1000000; i > 0; i /= 10)
#else
    for (int i = 1; i <= 10; i++)
#endif
    {
        int cur_bit = count_bit(i);
        std::cout << i;
        int dif = last_bit - cur_bit;

        if (dif > 0)
            std::cout << std::string(dif, ' ');

        std::cout << "\r";
        last_bit = cur_bit;
        sleep(1);
    }

    // 输出换行并恢复光标(光标不见了可以在终端执行 echo -e "\033[?25h" 就可以了)
    std::cout << std::endl << "\033[?25h";
}

这次来个跨度比较大的迭代输出,这样可以更加直观看到我们的程序已经修改正确,如图1-3所示:

在这里插入图片描述

图1-3

2、在文件中就地覆盖输出字符

前面做了一个在终端就地覆盖输出字符的程序,现在来探讨下在文件中就地覆盖字符该怎么做。首先,试试第一节那个方法可不可以直接使用,程序如下:

#include <iostream>
#include <fstream>
#include <unistd.h>

int count_bit(int number)
{
    int count = 1;
    while (number /= 10)
    {
        count++;
    }
    return count;
}

int main(int argc, char* argv[])
{
    std::ofstream ofs("test", std::ios::out);
    if (!ofs)
    {
        std::cout << "打开文件出错" << std::endl;
        return -1;
    }

    int last_bit = 0;
#if 1
    for (int i = 1000000; i > 0; i /= 10)
#else
    for (int i = 1; i <= 10; i++)
#endif
    {
        int cur_bit = count_bit(i);
        ofs << i;
        int dif = last_bit - cur_bit;

        if (dif > 0)
            ofs << std::string(dif, ' ');

        ofs << "\r";
        last_bit = cur_bit;
        sleep(1);
    }
}

输出文件内容如下:

1000000
100000
10000
1000
100
10
1

看来不能直接使用了,得另辟蹊径了。设计思路如下:

  1. 我们以读写的方式打开文件,如果文件不存在则创建(这里要注意不要用追加方式打开,不然就不能自由通过设置偏移量来达到对局部进行写入操作了,因为以追加打来文件之后写操作的偏移就失效了)
  2. 打开文件后,先把原先的内容记录下来(假设我们文件只有一行内容,记录着一个数字),然后对这个值进行各种操作(增加、减少都行)
  3. 操作完成之后,通过设置偏移量到文件开头,把数字写回去文件中,达到覆盖前面内容的目的

测试程序如下:

#include <iostream>
#include <fstream>
#include <unistd.h>

int count_bit(long number)
{
    int count = 1;
    while (number /= 10)
    {
        count++;
    }
    return count;
}

int main(int argc, char* argv[])
{
    std::fstream f;
    f.open("test", std::ios::out | std::ios::in);
    if (!f.is_open())
    {
        f.open("test", std::ios::out | std::ios::in | std::ios::trunc);
        if (!f.is_open())
        {
            std::cout << "打开文件出错" << std::endl;
            return -1;
        }
    }

    std::string line;
    long number;
    if (std::getline(f, line) == 0)
    {
        number = 1000000;
        std::cout << "第一次打开文件,设置初始值为1000000" << std::endl;
    }
    else
    {
        number = atol(line.c_str());
        std::cout << "打开文件成功,读取到的初始值为" << number << std::endl;
    }

    int last_bit = count_bit(number);
    // 这里自由发挥,加减乘除随便弄
    number /= 10;
    if (number == 0)
        number = 1000000;
    int cur_bit = count_bit(number);
    int dif = last_bit - cur_bit;

    // 清除流状态,必须加
    f.clear();
    f.seekp(0, std::ios::beg);
    f << number;
    if (dif > 0)
        f << std::string(dif, ' ');
}

这里就不贴结果图了,大家可以自行去尝试一下,就是简单地通过偏移写指针来达到往指定区域写入的内容的目的,这样也能覆盖掉原先的内容了。

3、总结

本文讲了两个简单的例子,第一个例子可以用作终端对某些操作进行倒计时或计数;第二个例子可以用于每天简单地记录某些批处理任务执行的次数,比如爬虫爬了多少内容之类的,当然其它语言大家就得按着这个思路自己去改改了。要注意这个也只能做点简单的记录了,复杂的记录还是得做一个规范的日志文件。

最后,如果大家觉得本文写得好的话麻烦点赞收藏关注一下谢谢,也可以关注该专栏,以后会有更多优质文章输出的。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章           查看所有文章
加:2021-07-07 11:40:49  更:2021-07-07 11:41:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 14:48:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码