[C++] Biblioteca de clases de secuencias de E/S

E/S

La entrada y salida de datos (entrada/salida se abrevia como E/S), y la entrada y salida de dispositivos de entrada estándar y dispositivos de salida estándar se conoce como E/S estándar. La entrada y salida de archivos en el disco de almacenamiento externo se conoce como E/S de archivo. La entrada y salida al espacio de almacenamiento de cadena especificado en la memoria se conoce como E/S de cadena.

fluir

El proceso de entrada y salida de datos se puede visualizar como un flujo. Las operaciones que obtienen datos de un flujo se denominan "obtener" (operaciones de entrada). Las operaciones que agregan datos a una secuencia se denominan operaciones de "inserción" (salida).

Sistema de herencia de la biblioteca de clases de flujo

inserte la descripción de la imagen aquí

  • La biblioteca de clases de flujo tiene dos clases base paralelas: streambuf y clase ios, y todas las clases de flujo usan una de las dos como clase base.
  • La clase streambuf proporciona operaciones de bajo nivel en el búfer: configurar el búfer, operar en el puntero del búfer, almacenar/recuperar caracteres en el búfer.
  • Las clases ios_base e ios registran el estado de la transmisión y admiten la conversión formateada o sin formato de la entrada/salida del búfer del streambuf.
  • strstreambuf: use una cadena para guardar una secuencia de caracteres. Amplía streambuf para realizar operaciones de inserción y extracción de búfer.
  • filebuf: use un archivo para guardar secuencias de caracteres. Incluye abrir archivos, leer/escribir y encontrar personajes.

Cuatro objetos de entrada y salida

C++ define cuatro objetos de clase para que los usuarios realicen operaciones de E/S estándar: cin, cout, cerr y clog. cin es un objeto de la clase de flujo istream, que representa el teclado del dispositivo de entrada estándar, y los tres últimos son objetos de la clase de flujo ostream. cout significa monitor de dispositivo de salida estándar. cerr y clog tienen el mismo significado, ambos representan la pantalla del dispositivo de salida del mensaje de error.

Funcionamiento de la corriente ostream

1.operador<<

¿Por qué se puede usar consecutivamente la operación <<? <<El valor de retorno es una referencia a ostream, puede usar <<sobrecarga continuamente. << Proporciona sobrecarga de tipos básicos.

2.poner

La operación put genera un solo carácter y devuelve una referencia a un ostream.

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

3.escribir

La operación de escritura genera la longitud especificada del búfer y devuelve una referencia al ostream.

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

Funcionamiento de la corriente istream

1.operador>>

El valor devuelto es una referencia a un istream, que se puede sobrecargar continuamente con >>. >> Proporciona sobrecarga de tipos básicos.

2.obtener

La operación de obtención lee un solo carácter y devuelve un número entero como el código ASCII del carácter.

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

También puede recibir una referencia.

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

3.getline

La operación getline lee una línea (se encontró con la tecla Intro). Devuelve una referencia al objeto istream. La diferencia entre la operación getline() y >>: getline obtiene una línea completa, y >> se detiene cuando encuentra un espacio.

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

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

4.leer

La operación de lectura devuelve una referencia a un objeto istream, la iluminación de los caracteres en blanco es correcta y el número especificado de caracteres se lee antes del final.

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

5. echar un vistazo y retroceder

peek mira sin leer; putback agrega un carácter a la secuencia.

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

flujo de archivos

ofstream, derivado de ostream, se usa para escribir archivos.
ifstream, derivado de istream, se usa para leer archivos.
fstream, derivado de iostream, se usa para leer y escribir archivos.

abrir un archivo

Después de que se haya declarado el objeto de flujo, el archivo se puede abrir usando la función open(). La apertura de un archivo es para establecer una conexión entre la secuencia y el archivo. Prototipo de función:

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

mode indica el modo de apertura de archivos, modo de protección prot. Hay 5 formas de juzgar si el archivo se abrió con éxito:

#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 apertura de archivos

método abierto describir
iso::en Abrir un archivo para lectura (predeterminado para ifstream)
iso::fuera Abra un archivo para escribir (el valor predeterminado para ofstream)
iso::aplicación encontrar el final del archivo antes de escribir
iso::ate colocar el archivo al final del archivo inmediatamente después de abrir el archivo
iso::tronco descartar el contenido del archivo actual
iso::nocreate (ya no es compatible) Si el archivo que se va a abrir no existe, llamar a la función open() con esta función no funcionará
iso::noreplace (ya no se admite) Si el archivo que se va a abrir ya existe, intentar abrirlo con la función open() devolverá un error
iso::binario Abra un archivo en forma binaria, el valor predeterminado es un archivo 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 */共享读取,独占写入

Notas sobre la apertura de archivos

  • La apertura de archivos también se puede abrir a través del constructor, por ejemplo:
ofstream fout("test.txt,ios::out");
  • El método de apertura del archivo puede ser una de las constantes de enumeración anteriores o una expresión OR bit a bit compuesta por varias constantes de enumeración.

  • Cuando se utiliza la función de miembro abierto para abrir un archivo, si el archivo especificado por el parámetro de puntero de carácter no existe, se crea el archivo.

  • Cuando el método abierto no contiene la opción ios::ate o ios::app, el puntero del archivo se mueve automáticamente al principio del archivo, es decir, la dirección del byte es 0.

  • En efecto, especificar el modo out de ofstream es equivalente a especificar los modos out y trunc.

  • De forma predeterminada, los objetos fstream se abren tanto en modo de entrada como de salida.

  • No se vacía cuando el archivo se abre tanto con la entrada como con la salida.

  • Si solo se usa el modo de salida sin especificar el modo de entrada, el archivo se vaciará de los datos existentes.

  • Si out y app se especifican al mismo tiempo, no se borrará.

  • Si se especifica el modo trunc al abrir el archivo, el archivo también se borrará independientemente de si se especifica el modo in al mismo tiempo.

estado de flujo

método abierto describir
ios::buen bit Todo funciona bien, no se producen errores y no hay fin de entrada
ios::eofbit fin de entrada
ios::fallo Una operación de E/S falló, principalmente debido a datos ilegales (como una letra encontrada al intentar leer un número). La secuencia se puede seguir utilizando y el bit de falla también se establecerá al final de la entrada.
ios::malo Se ha producido un error fatal (quizás físico). la transmisión no estará disponible.

En correspondencia con cada bit de estado de esta palabra indicadora, la clase ios también proporciona las siguientes funciones miembro para detectar o establecer el estado de la transmisión:

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

Para mejorar la confiabilidad del programa, es necesario detectar si la operación del flujo de E/S es normal en el programa. Cuando se detecta un error en una operación de transmisión, se puede usar el manejo de excepciones para resolver el problema.

cerrar archivo

Cada clase de secuencia de archivos proporciona una función miembro close() para cerrar el archivo. Función: cuando finaliza la operación del archivo abierto, debe cerrarse, de modo que la secuencia del archivo se desconecte del archivo físico correspondiente y pueda garantizar que el contenido salga al búfer del archivo al final, sin importar si esté lleno o no, se escribirá inmediatamente en el archivo físico correspondiente. Después de cerrar el archivo correspondiente a la secuencia de archivos, también puede usar la secuencia de archivos para llamar a la función de miembro abierto para abrir otros archivos. Lo mejor es borrarlo primero.

archivo de lectura y escritura

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. poner y recibir

#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. leer y escribir

La siguiente es una introducción a la lectura y escritura de archivos binarios.

4. La diferencia entre el modo de texto y el modo binario

Si el archivo se abre como texto, al escribir caracteres, la conversión se realizará cuando se encuentre \n. La plataforma Windows \n se convertirá a \r\n, la plataforma Linux permanecerá sin cambios y el sistema mac \n se convertirá a \r. \r no hacer ninguna conversión. Si el archivo se abre en modo binario, los caracteres se escriben sin conversión. Abrir un archivo como texto también puede escribir datos binarios y abrir un archivo como binario también puede escribir texto. Que los datos escritos sean binarios o texto no tiene nada que ver con el método de apertura, sino con la función utilizada para escribir. Para escribir datos binarios, se debe usar la escritura y se debe leer la lectura correspondiente.

Leer y escribir archivos binarios

Los archivos binarios son diferentes de los archivos de texto y se pueden usar para cualquier tipo de archivo, incluidos los archivos de texto. La lectura y escritura de archivos binarios puede usar la función miembro read() heredada de la clase istream y la función miembro write() heredada de la clase ostream. Utilice la constante de enumeración ios::binary al abrir el archivo, por ejemplo:

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;
}

Archivo de lectura y escritura cuando la cadena es lo suficientemente larga

#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;
}

Puntero de actividad de flujo de archivo actual

Los punteros de flujo de archivos se utilizan para realizar un seguimiento de dónde ocurren las operaciones de E/S. Cada vez que se lee o se escribe un carácter en la transmisión, el puntero de actividad actual avanza. Cuando el método abierto no contiene la opción ios::ate o ios::app, el puntero del archivo se mueve automáticamente al principio del archivo, es decir, la dirección del byte es 0.

Lectura y escritura aleatoria de archivos seekp y seekg

  • seekp: Establezca la posición del puntero del flujo de archivos del flujo de archivos de salida.
  • seekg: Establezca la posición del puntero del flujo de archivos del flujo de archivos de entrada.

Parámetros de la función: pos nueva posición del puntero del flujo de archivos, apagado necesita valor de desplazamiento, posición de inicio de búsqueda de directorios.

Lectura y escritura aleatoria de archivos tellp y tellg

  • tellp: obtiene la posición actual del puntero del flujo del archivo de salida en bytes.
  • Tellg: Obtiene la posición actual del puntero del flujo del archivo de entrada en bytes.

El valor de retorno de la función es en realidad un tipo largo.

#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;
}

buscar_dir

El parámetro dir se usa para ubicar el puntero del flujo de archivos y representa la posición inicial de la búsqueda. Tipos de enumeración definidos en ios:

enum seek_dir{
    
    beg,cur,end};

beg indica la posición inicial del flujo de archivos, cur indica la posición actual del flujo de archivos y end indica la posición final del flujo de archivos.

Formateo del flujo de salida

El formateo de la entrada y salida de datos se controla utilizando los manipuladores proporcionados en los archivos de encabezado del sistema. Simplemente utilícelos como objetos de salida del operador de inserción <<. 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;
}

El formato se controla llamando a funciones miembro de la secuencia, como setf, unsetf, ancho, relleno, precisión, etc. La ventaja es que mientras configura el formato, puede volver a la configuración anterior, lo cual es conveniente para restaurar la configuración original.

#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;
}

Supongo que te gusta

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