[C++] Biblioteca de classe de fluxo de E/S

E/S

A entrada e saída de dados (entrada/saída é abreviada como E/S), e a entrada e saída de dispositivos de entrada padrão e dispositivos de saída padrão são referidos como E/S padrão. A entrada e a saída de arquivos no disco de armazenamento externo são chamadas de E/S de arquivo. A entrada e a saída para o espaço de armazenamento de string especificado na memória são chamadas de E/S de string.

fluxo

O processo de entrada e saída de dados pode ser visualizado como um fluxo. As operações que obtêm dados de um fluxo são chamadas de "buscar" (operações de entrada). As operações que adicionam dados a um fluxo são chamadas de operações de "inserção" (saída).

Sistema de Herança da Biblioteca de Classes de Fluxo

insira a descrição da imagem aqui

  • A biblioteca de classe stream tem duas classes base paralelas: streambuf e classe ios, e todas as classes stream usam uma das duas como classe base.
  • A classe streambuf fornece operações de baixo nível no buffer: configurar o buffer, operar no ponteiro do buffer, armazenar/recuperar caracteres no buffer.
  • As classes ios_base e ios registram o estado do stream e suportam a conversão formatada ou não formatada da entrada/saída do buffer do streambuf.
  • strstreambuf: Use uma string para salvar uma sequência de caracteres. Estende streambuf para executar operações de extração e inserção de buffer.
  • filebuf: Use um arquivo para salvar sequências de caracteres. Inclui abrir arquivos, ler/escrever e localizar caracteres.

Quatro objetos de entrada e saída

C++ define quatro objetos de classe para que os usuários executem operações de E/S padrão: cin, cout, cerr e clog. cin é um objeto da classe istream stream, representando o teclado do dispositivo de entrada padrão, e os últimos três são objetos da classe ostream stream. cout significa monitor de dispositivo de saída padrão. cerr e clog têm o mesmo significado, ambos representam a exibição do dispositivo de saída da mensagem de erro.

Operação do fluxo ostream

1.operador<<

Por que a operação << pode ser usada consecutivamente? <<O valor de retorno é uma referência ao ostream, você pode usar <<overload continuamente. << Fornece sobrecarga de tipos básicos.

2.coloque

A operação put gera um único caractere e retorna uma referência a um ostream.

cout.put('A').put('B').put('C');

3.escrever

A operação de gravação gera o comprimento especificado do buffer e retorna uma referência ao ostream.

char buf[] = "testing!!!";
cout.write(buf, 8);

Operação do fluxo istream

1.operador>>

O valor de retorno é uma referência a um istream, que pode ser continuamente sobrecarregado com >>. >> Fornece sobrecarga de tipos básicos.

2.obter

A operação get lê um único caractere e retorna um inteiro como o código ASCII do caractere.

int ch = cin.get();
cout << ch << endl;

Também pode receber uma referência.

char ch, ch2;
cin.get(ch).get(ch2);
cout << ch << " " << ch2 << endl;

3.getline

A operação getline lê uma linha (encontrada a tecla Enter). Retorna uma referência ao objeto istream. A diferença entre a operação getline() e >>: getline obtém uma linha inteira e >> para ao encontrar um espaço.

char buf[10] = {
    
     0 };
cin.getline(buf, 10);
cout << buf << endl;

char buf2[10] = {
    
     0 };
cin >> buf2;
cout << buf2 << endl;

4.ler

A operação de leitura retorna uma referência a um objeto istream, a iluminação dos caracteres em branco está correta e o número especificado de caracteres é lido antes do final.

char buf[10] = {
    
     0 };
cin.read(buf, 5);
cout << buf << endl;

5. espreitar e colocar de volta

peek peeks sem ler; putback adiciona um caractere ao stream.

char c[10], c2, c3;
c2 = cin.get();
c3 = cin.get();
cin.putback(c2);
cin.getline(&c[0], 9);
cout << c << endl;

fluxo de arquivo

ofstream, derivado de ostream, é usado para gravar arquivos.
ifstream, derivado de istream, é usado para ler arquivos.
fstream, derivado de iostream, é usado para ler e gravar arquivos.

abra um arquivo

Depois que o objeto stream foi declarado, o arquivo pode ser aberto usando a função open(). A abertura de um arquivo é para estabelecer uma conexão entre o fluxo e o arquivo. Protótipo de função:

void open(const char* filename,int mode = ios::out,int prot = _SH_DENYNO);

modo indica o modo de abertura de arquivo, modo de proteção prot. Existem 5 maneiras de julgar se o arquivo foi aberto com sucesso:

#include <iostream>
#include <fstream>
#include <cassert>
using namespace std;

int main()
{
    
    
    ofstream fout;
    fout.open("test.txt");
    //1
    if (fout.is_open())
    {
    
    
        cout << "succ" << endl;
    }
    else
        cout << "failed" << endl;
    //2
    if (fout.good())
    {
    
    
        cout << "succ" << endl;
    }
    else
        cout << "failed" << endl;
    //3
    if (fout)
    {
    
    
        cout << "succ" << endl;
    }
    else
        cout << "failed" << endl;

    //4
    if (!fout)
    {
    
    
        cout << "failed" << endl;
    }
    else
        cout << "succ" << endl;

    //推荐使用断言方式
    assert(fout);

    fout.close();
    return 0;
}

modo de abrir arquivo

método aberto descrever
iso::em Abra um arquivo para leitura (padrão para ifstream)
iso::fora Abra um arquivo para gravação (o padrão para ofstream)
iso::aplicativo encontre o fim do arquivo antes de escrever
iso::ate posicione o arquivo no final do arquivo imediatamente após abrir o arquivo
iso::tronco descartar o conteúdo do arquivo atual
iso::nocreate (não é mais suportado) Se o arquivo a ser aberto não existir, chamar a função open() com esta função não funcionará
iso::noreplace (não é mais suportado) Se o arquivo a ser aberto já existir, tentar abri-lo com a função open() retornará um erro
iso::binário Abra um arquivo em formato binário, o padrão é um arquivo de texto

modo protegido

#define _SH_DENYRW      0x10    /* deny read/write mode */拒绝对文件进行读写
#define _SH_DENYWR      0x20    /* deny write mode */拒绝写入文件
#define _SH_DENYRD      0x30    /* deny read mode */拒绝文件的读取权限
#define _SH_DENYNO      0x40    /* deny none mode */读取和写入许可
#define _SH_SECURE      0x80    /* secure mode */共享读取,独占写入

Observações sobre a abertura do arquivo

  • A abertura do arquivo também pode ser aberta através do construtor, por exemplo:
ofstream fout("test.txt,ios::out");
  • O método de abertura do arquivo pode ser uma das constantes de enumeração acima ou uma expressão OR composta por várias constantes de enumeração.

  • Ao usar a função de membro aberta para abrir um arquivo, se o arquivo especificado pelo parâmetro de ponteiro de caractere não existir, o arquivo será criado.

  • Quando o método open não contém a opção ios::ate ou ios::app, o ponteiro do arquivo é movido automaticamente para o início do arquivo, ou seja, o endereço do byte é 0.

  • Na verdade, especificar o modo out of ofstream é equivalente a especificar os modos out e trunc.

  • Por padrão, os objetos fstream são abertos nos modos de entrada e saída.

  • Não é esvaziado quando o arquivo é aberto com entrada e saída.

  • Se apenas o modo out for usado sem especificar o modo in, o arquivo será esvaziado dos dados existentes.

  • Se out e app forem especificados ao mesmo tempo, não será apagado.

  • Se o modo de truncamento for especificado ao abrir o arquivo, o arquivo também será limpo independentemente de o modo de entrada ser especificado ao mesmo tempo.

estado de fluxo

método aberto descrever
ios::goodbit Tudo funciona bem, sem erros e sem fim de entrada
ios::eofbit fim da entrada
ios::failbit Uma operação de E/S falhou, principalmente devido a dados ilegais (como uma letra encontrada ao tentar ler um número). O fluxo pode continuar a ser usado e o bit de falha também será definido no final da entrada.
ios::badbit Ocorreu um erro fatal (talvez físico). fluxo não estará disponível.

Correspondendo a cada bit de status dessa palavra sinalizadora, a classe ios também fornece as seguintes funções de membro para detectar ou definir o status do fluxo:

bool rdstate();             //返回流的当前状态标志字
bool eof();                 //返回非0值表示到达文件尾
bool fail();                //返回非0值表示操作失败
bool bad();                 //返回非0值表示出现错误
bool good();                //返回非0值表示流操作正常
bool clear(int flag=0);     //将流的状态设置为flag

Para melhorar a confiabilidade do programa, é necessário detectar se o funcionamento do fluxo de I/O está normal no programa. Quando um erro é detectado em uma operação de fluxo, o tratamento de exceção pode ser usado para resolver o problema.

fechar arquivo

Cada classe de fluxo de arquivo fornece uma função de membro close() para fechar o arquivo. Função: Quando a operação do arquivo aberto terminar, ele precisa ser fechado, para que o fluxo do arquivo seja desconectado do arquivo físico correspondente e possa garantir que o conteúdo seja enviado para o buffer do arquivo no final, não importa se estiver cheio ou não, será gravado imediatamente no arquivo físico correspondente. Depois que o arquivo correspondente ao fluxo de arquivo for fechado, você também pode usar o fluxo de arquivo para chamar a função de membro aberta para abrir outros arquivos. É melhor limpá-la primeiro.

arquivo ler e escrever

1.>>和<<

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    
    
    ofstream fout("test.txt");
    fout << "abcd" << " " << 200;
    fout.close();

    ifstream fin("test.txt");
    string s;
    int n;
    fin >> s >> n;
    cout << s << " " << n << endl;

    return 0;
}

2. coloque e pegue

#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

int main()
{
    
    
    ofstream fout("test2.txt");
    char ch;

    assert(fout);

    for (int i = 0; i < 26; i++)
    {
    
    
        ch = 'A' + i;
        fout.put(ch);
    }
    fout.close();

    ifstream fin("test2.txt");
    while (fin.get(ch))
    {
    
    
        cout << ch;
    }

    return 0;
}

3. ler e escrever

O seguinte é uma introdução à leitura e gravação de arquivos binários.

4. A diferença entre o modo texto e o modo binário

Se o arquivo for aberto como texto, ao escrever caracteres, a conversão será executada ao encontrar \n. A plataforma Windows \n será convertida para \r\n, a plataforma linux permanecerá inalterada e o sistema mac \n será convertido para \r. \r não faz nenhuma conversão. Se o arquivo for aberto no modo binário, os caracteres serão gravados sem conversão. Abrir um arquivo como texto também pode gravar dados binários e abrir um arquivo como binário também pode gravar texto. Se os dados escritos são binários ou texto não tem nada a ver com o método de abertura, mas com a função usada para escrever. Para gravar dados binários, a gravação deve ser usada e a leitura correspondente deve ser lida.

Lendo e gravando arquivos binários

Arquivos binários são diferentes de arquivos de texto e podem ser usados ​​para qualquer tipo de arquivo, incluindo arquivos de texto. A leitura e gravação de arquivos binários podem usar a função de membro read() herdada da classe istream e a função de membro write() herdada da classe ostream. Use a constante de enumeração ios::binary ao abrir o arquivo, por exemplo:

ofstream fout("binary.dat",ios::out|ios::binary);
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

struct Test
{
    
    
    int a;
    int b;
};
int main()
{
    
    
    Test test = {
    
     100,200 };
    ofstream fout("binary.txt", ios::out | ios::binary);
    fout.write(reinterpret_cast<char*>(&test),sizeof(Test));
    fout.close();

    Test test2;
    ifstream fin("binary.txt", ios::in | ios::binary);
    fin.read(reinterpret_cast<char*>(&test2),sizeof(Test));
    cout << test2.a << " " << test2.b << endl;

    return 0;
}

Arquivo lido e gravado quando a string é longa o suficiente

#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

struct Test
{
    
    
    int x;
    string a;
    string b;
};
int main()
{
    
    
    Test t1;
    t1.x = 100;
    t1.a = "asdfsdafasfdasdfasdffsdfsdafadsadsfdfsfdsafdasfdsadfasdsfaasfddsfsadfsdfafdsasadffads";
    t1.b = "qwerqwerqrwewqrrqewewrewrqrqewerwqrewqqwerrweqrewqreqwerqwrqewrqweqrwerweqqrwerqwerwesfadsfafdfadsasfasdafsqrw";
    ofstream fout("test4.txt", ios::out | ios::binary);
    fout.write((char*)(&t1.x),sizeof(int));
    int len;
    len = t1.a.length();
    fout.write((char*)&len, sizeof(int));
    fout.write(t1.a.data(), t1.a.length());
    len = t1.b.length();
    fout.write((char*)&len, sizeof(int));
    fout.write(t1.b.data(), t1.b.length());
    fout.close();

    ifstream fin("test4.txt", ios::in | ios::binary);
    Test t2;
    fin.read((char*)(&t2.x),sizeof(int));
    fin.read((char*)(&len), sizeof(int));
    t2.a.resize(len);
    fin.read(&t2.a[0], len);
    fin.read((char*)(&len), sizeof(int));
    t2.b.resize(len);
    fin.read(&t2.b[0], len);
    cout << t2.x << " " << t2.a << " " << t2.b << endl;

    return 0;
}

Ponteiro de atividade de fluxo de arquivo atual

Ponteiros de fluxo de arquivo são usados ​​para rastrear onde ocorrem as operações de E/S. Sempre que um caractere é lido ou gravado no fluxo, o ponteiro de atividade atual é avançado. Quando o método open não contém a opção ios::ate ou ios::app, o ponteiro do arquivo é movido automaticamente para o início do arquivo, ou seja, o endereço do byte é 0.

Leitura e gravação aleatória de arquivos seekp e seekg

  • seekp: Defina a posição do ponteiro do fluxo de arquivo do fluxo de arquivo de saída.
  • seekg: Defina a posição do ponteiro do fluxo de arquivo do fluxo de arquivo de entrada.

Parâmetros de função: pos nova posição do ponteiro do fluxo de arquivo, off precisa de valor de deslocamento, posição inicial de pesquisa de dir.

Leitura e gravação aleatória de arquivos tellp e tellg

  • tellp: Obtém a posição atual do ponteiro do fluxo do arquivo de saída em bytes.
  • tellg: Obtém a posição atual do ponteiro do fluxo do arquivo de entrada em bytes.

O valor de retorno da função é, na verdade, um tipo longo.

#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

struct Test
{
    
    
    int x;
    string a;
    string b;
};
int main()
{
    
    
    ifstream fin("test5.txt");
    assert(fin);
    fin.seekg(2);

    char ch;
    fin.get(ch);
    cout << ch << endl;

    fin.seekg(-1, ios::end);
    fin.get(ch);
    cout << ch << endl;

    fin.seekg(0, ios::end);
    streampos pos = fin.tellg();
    cout << pos << endl;

    return 0;
}

procurar_dir

O parâmetro dir é usado para localizar o ponteiro do fluxo de arquivo e representa a posição inicial da pesquisa. Tipos de enumeração definidos em ios:

enum seek_dir{
    
    beg,cur,end};

beg indica a posição inicial do fluxo de arquivo, cur indica a posição atual do fluxo de arquivo e end indica a posição final do fluxo de arquivo.

Formatação do fluxo de saída

A formatação da entrada e saída de dados é controlada usando os manipuladores fornecidos nos arquivos de cabeçalho do sistema. Basta utilizá-los como objetos de saída do operador de inserção <<. Como setiosflags, setw, setfill, setprecision, hex, oct, etc.

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    
    
    int n = 64;
    double d = 123.45;
    double d2 = 0.0187;

    //通过操纵子方式进行格式化输出
    cout << "====================宽度控制====================" << endl;
    cout << n << "#" << endl;
    cout << setw(10) << n << "#" << endl;                                   //默认右对齐
    cout << setw(10) << n << "#" << n << endl;                              //宽度控制不会影响下一个输出

    cout << "====================对齐控制====================" << endl;
    cout << setw(10) << setiosflags(ios::left) << n << "#" << endl;         //设置左对齐
    cout << setw(10) << n << "#" << endl;                                   //对齐控制影响下一个输出
    cout << setw(10) << setiosflags(ios::right) << n << "#" << endl;        //设置右对齐
    cout << setw(10) << resetiosflags(ios::left) << n << "#" << endl;       //取消左对齐

    cout << "====================对齐控制====================" << endl;
    cout << setw(10) << setfill('?') << n << "#" << endl;
    cout << setw(10) << n << "#" << endl;                                   //填充控制影响下一个输出
    cout << setw(10) << setfill(' ') << n << "#" << endl;

    cout << "====================精度控制====================" << endl;
    cout << setprecision(4) << d << endl;                                   //保留四位有效数字
    cout << setprecision(2) << d2 << endl;
    cout << setiosflags(ios::fixed);
    cout << setprecision(4) << d << endl;                                   //保留小数点后四位
    cout << setprecision(2) << d2 << endl;

    cout << "====================进制输出====================" << endl;
    cout << n << endl;
    cout << dec << n << endl;
    cout << oct << n << endl;
    cout << hex << n << endl;
    cout << endl;

    cout << setiosflags(ios::showbase);
    cout << dec << n << endl;
    cout << oct << n << endl;
    cout << hex << n << endl;
    cout << endl;

    cout << setbase(10) << n << endl;
    cout << setbase(8) << n << endl;
    cout << setbase(16) << n << endl;
    return 0;
}

O formato é controlado pela chamada de funções de membro do fluxo, como setf, unsetf, largura, preenchimento, precisão, etc. A vantagem é que, ao definir o formato, você pode retornar às configurações anteriores, o que é conveniente para restaurar as configurações originais.

#include <iostream>
using namespace std;

int main()
{
    
    
    int n = 64;
    double d = 123.45;
    double d2 = 0.0187;

    cout << "====================宽度控制====================" << endl;//宽度控制不会影响下一个输出
    cout << n << "#" << endl;

    cout.width(10);
    cout << n << "#" << endl;

    cout << n << "#" << endl;

    cout << "====================对齐控制====================" << endl;//对齐控制影响下一个输出
    cout.width(10);
    cout.setf(ios::left);
    cout << n << "#" << endl;

    cout.width(10);
    cout << n << "#" << endl;

    cout.width(10);
    cout.unsetf(ios::left);
    cout << n << "#" << endl;

    cout.width(10);
    cout.setf(ios::right);
    cout << n << "#" << endl;

    cout << "====================对齐控制====================" << endl;//填充控制影响下一个输出
    cout.width(10);
    cout.fill('?');
    cout << n << "#" << endl;

    cout.width(10);
    cout << n << "#" << endl;

    cout.width(10);
    cout.fill(' ');
    cout << n << "#" << endl;

    cout << "====================精度控制====================" << endl;
    cout.precision(4);//保留四位有效数字
    cout << d << endl;
    cout.precision(2);
    cout << d2 << endl;

    cout.setf(ios::fixed);
    cout.precision(4);//保留小数点后四位
    cout << d << endl;
    cout.precision(2);
    cout << d2 << endl;

    cout << "====================进制输出====================" << endl;
    cout.setf(ios::showbase);
    cout << n << endl;
    cout.unsetf(ios::dec);
    cout.setf(ios::oct);
    cout << n << endl;

    cout.unsetf(ios::showbase);
    cout << n << endl;
    return 0;
}

Acho que você gosta

Origin blog.csdn.net/weixin_43912621/article/details/131024872
Recomendado
Clasificación