zoukankan      html  css  js  c++  java
  • c++输入输出流

    输入输出流类关系图

    iostream头文件中4种流对象

    对象 含义 对应设备 对应的类 C语言对应文件
    cin 标准输入流 键盘 istream_withassign stdin
    cout 标准输出流 控制台 ostream_withassign stdout
    cerr 标准错误流 控制台 ostream_withassign stderr
    clog 标准错误流 控制台 ostream_withassign stderr

      1. cout流在内存中对应开辟了一个缓存区,用来存放流中的数据,当向cout流插入一个endl时,不论缓冲区是否已满,都立即输出流中的所有数据,然后插入一个换行符,并刷新流(清空缓冲区), 注意如果插人一个换行符” “(如cout<<a<<" "),则只输出和换行,而不刷新cout 流(但并不是所有编译系统都体现出这一区别)

      2.cout 流通常是传送到显示器输出,但也可以被重定向 输出到磁盘文件,而cerr流中的信息只能在显示器输出,cerr是不经过缓冲区,直接向显示器上输出有关信息,而clog中的信息存放在缓冲区中,缓冲区满后或遇endl时向显示器输出

    1. 标准输入流cin

      (1)常用函数

    cin.get() 返回单个字符
    cin.get(char cval) 返回单个字符
    cin.get(_Elem *_Str, streamsize _Count) 返回Count字符的字符串
    cin.get(Elem *_Str,count, _Elem _Delim) Delim为结尾符
    cin.getline(char *_Str, Count, char _Delim)  
    cin.ignore() 读取字符并忽略指定字符
    cin.peek() 检查下一个输入的字符,不会把字符从流中移除
    cin.putback(char cVal)  返回一个字符给一个流
    1. 使用cin从流中读出的字符,流中就没有字符了,再次读取时只能读取剩下的
    2. 缓冲区只有在遇到EOF、手动敲回车,流缓存区满时,才能将流中的字符全部读出(即清空缓存区)

      (2)示例

    #include "stdio.h"
    #include <iostream>
    using namespace std;
    
    void main()
    {
        // 从流中读取个字符然后再放进去
        char cVal = cin.get();
        cin.putback(cVal);
        
        // 判断流中的第一个字符是不是刚放进去的字符
        if (cin.peek() == cVal)
        {
            cout << "流中的第一个字符是刚放进去的字符" << endl;
        }
        else
        {
            cout << "流中的第一个字符不是刚放进去的字符" << endl;
        }
    
        // 从流中读取10个字符
        char cBuff[11] = {0};
        cin.get(cBuff,11);  // 注意这里是11
    
        // 从流中忽略5个字符,再读取10个字符
        cin.ignore(5);
        char cBuff1[11] = {0};
        cin.get(cBuff1, 11, EOF);
    
        // 读取剩下的字符
        char cBuff2[100] = {0};
        cin.get(cBuff2, 100);
    
        //输出读到的数据
        cout<<"第一个字符"<<cVal<<endl;
        cout<<"第一组 字符串:"<<cBuff<<endl;
        cout<<"第二组 字符串:"<<cBuff1<<endl;
        cout<<"剩下的字符串:"<<cBuff2<<endl;
    
        system("pause");
    
        return;
    }

    2. 标准输出流cout

      (1)用于控制输出格式的流成员函数

    流成员函数 作用相同的控制符 作用
    precision(n) setprecision(n) 设置实数的精度
    width(n) setw(n) 设置字符宽度
    fill(char cVal) setfill(char cVal) 设置填充字符
    setf() setiosflags() 设置输出各格式状态
    unsetf() resetiosflags() 终止已经设置的输出格式状态,在括号中应指定内容

      (2)设置格式状态的格式标志

    格式标志 作用
    ios::left 输出数据在本域宽范围内向左对齐
    ios::right 输出数据在本域宽范围内向右对齐
    ios::internal 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
    ios::dec 设置整数的基数为10
    ios:oct 设置整数的基数为8
    ios::hex 设置整数的基数为16
    ios::showbase 强制输出整数的基数(八进制以0开头,十六进制以0x开头)
    ios::showpoint 强制输出浮点数的小树和尾数0
    ios::uppercase 以科学计数法格式E和以十六进制输出字母时以大写表示
    ios::showpos 对正数显示‘+’号
    ios::scientific 浮点数以科学计数法格式输出
    ios::fixed 浮点数以定点格式(小数形式)输出
    ios::unitbuf 每次输出之后刷新所有的流
    ios::stdio 每次输出之后清除stdout/stderr
    eg : cout.setf( ios::dec );

           cout.setf(ios::hex,ios::basefield);【建议使用这种】

    需注意:
    1、fmtflags setf( fmtflags flags ); 使用这种,一定要先取消当前基【cout.unself()】,之后才可以设置新的基

     2、fmtflags setf( fmtflags flags, fmtflags needed ); 使用这种,第二个参数设为当前的基,或者当不知道当前基时,设为ios_base::basefield清除当前的所有可能的基

      (3)输入输出流的控制符

    控制符 作用
    dec 设置基数10
    oct 设置基数8
    hex 设置基数16
    setfill(c) 用字符填充
    setprecision(n) 设置精度
    setw(n) 设置宽度
    setiosflags(ios::fixed) 设置浮点数以固定的小数位数显示
    setiosflags(ios::scientific) 设置浮点数以科学计数法显示
    setiosflags(ios::skipws) 忽略前导的空格
    setiosflags(ios::left) 左对齐
    setiosflags(ios::right) 右对齐
    setiosflags(ios::uppercase) 数据以16进制输出时字母大写
    setiosflags(ios::lowercase) 数据以16进制输出时字母小写
    setiosflags(ios::showpos) 输出正数时给出+号
    如果使用了控制符,需要加头文件include<iomanip>

    文件输入输出流fstream

      ofstream, ifstream, fstream

      在头文件fstream中,在fstream类中,用open成员函数打开文件,实现类与文件的关联操作。

      - open(filename, mode, prot):对所属类进行用指定的参数进行特定的文件关联

                  几种打开方式(mode)(这些方式可以用 '|' 组合起来)

    1. 文件打开方式

    ios::in 读文件
    ios::out 写文件
    ios::app 所有写入附加在文件末尾
    ios::ate 打开一个已有文件,文件指针指向文件末尾
    ios::trunc 打开文件,若文件存在则删除全部数据,若文件不存在则建立新文件,如已指定ios::out方式,而未指定ios::app,ios::ate,ios::in,则默认此方法
    ios::binary 二进制打开文件

    2. 属性值设置

      打开文件的属性,这些方式可以用‘+’进行组合,这个参数可以省略不传

    0 普通文件,打开操作
    1 只读文件
    2 隐含文件
    4 系统文件

    3. 文件状态判断

    is_open() 文件是否正常打开
    bad() 读写过程中是否出错
    fail() 读写过程中是否出错
    eof() 读文件到达文件末尾,返回True
    good() 以上任何一个返回True,这个就返回False

    4. 流指针设置

      - 获得和设置流指针

        - 对于所有的输入输出流都有至少一个指针,指向下一个要操作的位置

          ofstream  put_point

          ifstream  get_point

          fstream  put_point和get_point

        - 获取流指针位置

          tellg(): 返回输入流指针的位置(返回类型long)

          tellp(): 返回输出流指针的位置(返回类型long)

        - 设置指针位置

          seekg(long  position):  设置输入流指针位置为第position个字符(文件首位置为开始位置)

          seekp(long  position):  设置输出流指针到指定位置

    istream &seekg(streamoff offset,seek_dir origin);
    ostream &seekp(streamoff offset,seek_dir origin);
    ios::beg:  文件开头
    ios::cur:  文件当前位置
    ios::end:  文件结尾

    字符串输入输出流sstringstream

      ostringstream:用于执行C风格字符串的输出操作

      istringstream:用于执行C风格字符串的输入操作

      stringstream:同时支持C风格字符串的输入输出操作

      例1:

    #include "stdio.h"
    #include <iostream>
    #include <sstream>
    using namespace std;
    
    void ostringstream_test()
    {
        ostringstream oss;
        oss << "this is test" << '	'<< 123456;
        cout << oss.str() << endl;
        oss.str("");  // 清空之前的内容
        // oss.clear(); // 并不能清空内存
        cout << oss.str() << endl;
    
        // 浮点数转换限制
        double dbVal = 123.123455677;
        oss << dbVal;
        cout << oss.str() << endl;
        oss.str("");
        oss.precision(9);
        oss.setf(ios::fixed, ios::basefield);  // 将浮点数的位数限定为小数点之后的位数
        oss << dbVal;
        cout << oss.str() << endl;
    }

      例2:

    void istringstream_test()
    {
        // 输入
        stringstream ss;
        ss << "this is test" << ' '<< 123456;
        cout << ss.str() << endl;
    
        // 输出
        string out;
        while (ss >> out)
        {
            cout << out.c_str() << endl;
        }
    }

    例:日志信息输出

    (1)功能思维导图

      

    (2)代码实现

    Logging.h
    #pragma once
    #include <stdio.h>
    #include <Windows.h>
    
    #define MAX_BUFFSIZE 8192
    namespace Logger
    {
        enum LOGMODE
        {
            CONSOLE = 0x1,
            LOGFILE = 0x2,
            CONSOLE_FILE=0x3
        };
    
        enum LOGLEVEL
        {
            INFO = 0,
            DEBUG
        };
    
        class CLogging
        {
        public:
            explicit CLogging();
            explicit CLogging(const int LogMode, char *pFileName=NULL, char *pFileMode=NULL);
            ~CLogging(void);
            void LogPrintf(char* pFormat, ...);
    
        private:
            inline void OutputLoginfo(const char *pBuff);
    
        private:
            TCHAR *m_pLogFileName;
            TCHAR *m_pLogFileMode;
            int m_LogMode;
            FILE *m_pFile;
            HANDLE m_hMuex;
        };
    }
    Logging.cpp
    #include "Logging.h"
    #include <time.h>
    
    namespace Logger
    {
        CLogging::CLogging(void)
        {
            m_pLogFileName = NULL;
            m_pLogFileMode = NULL;
            m_pFile = NULL;
            m_hMuex = NULL;
        }
    
        CLogging::CLogging( const int LogMode, char *pFileName, char *pFileMode ):
            m_LogMode(LogMode),m_pLogFileName(pFileName),m_pLogFileMode(pFileMode)
        {
            m_hMuex = CreateMutex(NULL, 0, NULL);
            m_pFile = NULL;
    
            switch (LogMode)
            {
            case CONSOLE:
                break;
            case LOGFILE:
            case CONSOLE_FILE:
                {
                    m_pFile = fopen(m_pLogFileName, pFileMode);
                    if (!m_pFile)
                    {
                        throw ("Open LogFile Error!");
                    }
                }
                break;
            }
        }
    
        CLogging::~CLogging(void)
        {
            if (m_pFile)
            {
                fclose(m_pFile);
            }
            if (m_hMuex!=NULL)
            {
                CloseHandle(m_hMuex);
            }
        }
    
        void CLogging::LogPrintf(char* pFormat, ... )
        {   
            DWORD nRet = WaitForSingleObject(m_hMuex, 5000);
            switch (nRet)
            {
            case WAIT_OBJECT_0:
                {
                    va_list args; 
                    char cText[MAX_BUFFSIZE] = {0}; 
                    va_start(args, pFormat); 
                    vsprintf(cText, pFormat, args); 
                    OutputLoginfo(cText); 
                    va_end(args); 
                    ReleaseMutex(m_hMuex);
                }
                break;
            case WAIT_TIMEOUT:
                break;
            case WAIT_FAILED:
                break;
            }
        }
    
        inline void CLogging::OutputLoginfo( const char *pBuff )
        {
            time_t CurrentTime;
            time(&CurrentTime);
            char TimeBuff[MAX_PATH] = {0};
            char cBuff[MAX_BUFFSIZE] = {0};
            // 根据日志级别的不同配置不同的显示信息
            strftime(TimeBuff, sizeof(TimeBuff), "%H:%M:%S",localtime(&CurrentTime) );
            //sprintf_s(cBuff, MAX_BUFFSIZE, "[%s] [%s: %s] %d entered
     %s", TimeBuff, __FILE__, __FUNCTION__, __LINE__, pBuff);
            sprintf_s(cBuff, MAX_BUFFSIZE, "[%s] [%s:] %d entered
     %s", TimeBuff, __FUNCTION__, __LINE__, pBuff);
            switch (m_LogMode)
            {
            case CONSOLE:
                printf(cBuff);
                break;
            case LOGFILE:
                fputs(cBuff, m_pFile);
                break;
            case CONSOLE_FILE:
                printf(cBuff);
                fputs(cBuff, m_pFile);
                break;
            }
        }
    }
    StopWatch.h
    #pragma once
    
    namespace Logger
    {
        class CStopwatch
        {
        private:
            // 64位有符号整数可以用INT64 _int64 LARGE_INTEGER表示
            LARGE_INTEGER m_nPerfFrequency;
            LARGE_INTEGER m_nPerFrefStart;
    
        public:
            CStopwatch(){QueryPerformanceFrequency(&m_nPerfFrequency); Start();}
            inline void Start(){QueryPerformanceCounter(&m_nPerFrefStart);}
    
            inline INT64 Now() const
            {
                LARGE_INTEGER nPerfNow;
                QueryPerformanceCounter(&nPerfNow);
                return ((nPerfNow.QuadPart - m_nPerFrefStart.QuadPart) * 1000) / m_nPerfFrequency.QuadPart;
            }
    
            inline INT64 NowInMicro() const
            {
                LARGE_INTEGER nPerfNow;
                QueryPerformanceCounter(&nPerfNow);
                return ((nPerfNow.QuadPart - m_nPerFrefStart.QuadPart) * 1000000) / m_nPerfFrequency.QuadPart;
            }
        };
    }
    test.cpp
    #include "stdio.h"
    #include "Logging.h"
    #include "StopWatch.h"
    using namespace Logger;
    
    #include <iostream>
    using namespace std;
    
    
    bool bThead1 = false;
    bool bThead2 = false;
    void TestFun1()
    {
        CLogging log(CONSOLE|LOGFILE, "D:\testlog.txt", "a+");
        for (int i = 0 ; i < 100; i ++)
        {
            log.LogPrintf("%s 0x%0x
    ", "hello", i);
        }
    }
    
    void TestFun2()
    {
        CLogging log(CONSOLE|LOGFILE, "D:\testlog.txt", "a+");
        for (int i = 101 ; i < 200; i ++)
        {
            log.LogPrintf("%s %0x
    ", "hello", i);
        }
    }
    
    DWORD WINAPI ThreadFun1(LPVOID lparam)
    {
        TestFun1();
        cout << "thread1 end" << endl;
        bThead1 = true;
        return 0;
    }
    DWORD WINAPI ThreadFun2(LPVOID lparam)
    {
        TestFun2();
    
        cout << "thread2 end" << endl;
        bThead2 = true;
        return 0;
    }
    
    int main()
    {
        CStopwatch watch;
        //TestFun();  单线程测试
        // 多线程测试
        DWORD lpThreadId1 = 0;
        DWORD lpThreadId2 = 1;
        HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun1, NULL, 0, &lpThreadId1);
        //HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun2, NULL, 0, &lpThreadId2);
        while(1)
        {
            if (bThead1 && bThead2)
            {
                break;
            }
        }
        cout <<"共用时:"<< watch.Now()<<"ms" << endl;
        return 0;
    }
  • 相关阅读:
    ASP.NET 2.0个性化配置(profile)
    03 创建虚拟机
    一些新的Blender的视频教程
    [转载]虚拟家庭存档文件修改方法
    [转载]游戏开发中常用的设计模式
    批处理for命令详解(转)
    [转载]高效软件开发团队的特征
    软件构架师的特点
    一点SICP(Structure and Interpretation of Computer Programs) 资料 (转载加整理)
    [译]游戏编程入门(by David Astle)
  • 原文地址:https://www.cnblogs.com/xiaobingqianrui/p/8777288.html
Copyright © 2011-2022 走看看