Compartir a través de


Redactar flujos

Una memoria auxiliar es un medio de almacenamiento, como un disco o memoria. Cada tipo de almacén de respaldo implementa su propia secuencia como una implementación de la clase Stream.

Cada tipo de secuencia lee y escribe los bytes desde y en su memoria auxiliar determinada. Los flujos que se conectan a las memorias auxiliares reciben el nombre de secuencias base. Las secuencias base tienen constructores con los parámetros necesarios para conectar el flujo a la memoria auxiliar. Por ejemplo, FileStream tiene constructores que especifican un parámetro de modo de acceso, que determina si el archivo se lee, se escribe en o en ambos.

El diseño de las clases System.IO proporciona la composición de flujos simplificada. Puede asociar las secuencias base a uno o varios flujos de paso a través que proporcionan la funcionalidad que desee. Puede asociar un lector o escritor al final de la cadena para que los tipos deseados se puedan leer o escribir con facilidad.

Requisitos previos

En estos ejemplos se usa un archivo de texto sin formato denominado data.txt. Este archivo debe contener texto.

Ejemplo: Cifrado y descifrado de datos de flujo

En el ejemplo siguiente se leen datos de un archivo, se cifran y, a continuación, se escriben los datos cifrados en otro archivo. La composición del flujo se usa para transformar los datos mediante un cifrado de desplazamiento básico. Cada byte que pasa por la secuencia tiene su valor cambiado por 80.

Advertencia

El cifrado usado en este ejemplo es básico y no seguro. No está diseñado para cifrar realmente los datos para su uso, pero se proporciona para demostrar la modificación de los datos a través de la composición del flujo.

Lee los datos de origen para el cifrado.

El código siguiente lee el texto de un archivo, lo transforma y, a continuación, lo escribe en otro archivo.

Sugerencia

Antes de revisar este código, sepa que el CipherStream es un tipo definido por el usuario. El código de esta clase se proporciona en la sección clase CipherStream.

void WriteShiftedFile()
{
    // Create the base streams for the input and output files
    using FileStream inputBaseStream = File.OpenRead("data.txt");
    using CipherStream encryptStream = CipherStream.CreateForRead(inputBaseStream);
    using FileStream outputBaseStream = File.Open("shifted.txt", FileMode.Create, FileAccess.Write);

    int intValue;

    // Read byte from inputBaseStream through the encryptStream (normal bytes into shifted bytes)
    while ((intValue = encryptStream.ReadByte()) != -1)
    {
        outputBaseStream.WriteByte((byte)intValue);
    }

    // Process is:
    //  (inputBaseStream -> encryptStream) -> outputBaseStream
}
Sub WriteShiftedFile()

    'Create the base streams for the input and output files
    Using inputBaseStream As FileStream = File.OpenRead("data.txt")
        Using encryptStream As CipherStream = CipherStream.CreateForRead(inputBaseStream)
            Using outputBaseStream As FileStream = File.Open("shifted.txt", FileMode.Create, FileAccess.Write)


                'Read byte from inputBaseStream through the encryptStream (normal bytes into shifted bytes)
                Dim intValue As Integer = encryptStream.ReadByte()
                While intValue <> -1

                    outputBaseStream.WriteByte(Convert.ToByte(intValue))

                    intValue = encryptStream.ReadByte()

                End While

            End Using
        End Using
    End Using

    'Process is:
    '  (inputBaseStream -> encryptStream) -> outputBaseStream
End Sub

Tenga en cuenta los siguientes aspectos sobre el código anterior:

  • Hay dos objetos FileStream:
    • El primer objeto FileStream (inputBaseStream variable) lee el contenido del archivo data.txt. Esta es la entrada de flujo de datos.
    • El segundo objeto FileStream (variableoutputBaseStream ) escribe datos entrantes en el archivo shifted.txt. Esta es la salida de flujo de datos.
  • El objeto CipherStream ( variableencryptStream ) encapsula el inputBaseStream, lo que inputBaseStream la secuencia base para encryptStream.

El flujo de entrada podría leerse directamente, escribir los datos en el flujo de salida, pero eso no transformaría los datos. En su lugar, el contenedor de flujo de entrada encryptStream se usa para leer los datos. A medida que se leen los datos de encryptStream, extrae del flujo base de inputBaseStream, lo transforma y lo devuelve. Los datos devueltos se escriben en outputBaseStream, que escribe los datos en el archivo shifted.txt.

Leer los datos transformados para el descifrado

Este código invierte el cifrado realizado por el código anterior:

void ReadShiftedFile()
{
    int intValue;

    // Create the base streams for the input and output files
    using FileStream inputBaseStream = File.OpenRead("shifted.txt");
    using FileStream outputBaseStream = File.Open("unshifted.txt", FileMode.Create, FileAccess.Write);
    using CipherStream unencryptStream = CipherStream.CreateForWrite(outputBaseStream);

    // Read byte from inputBaseStream through the encryptStream (shifted bytes into normal bytes)
    while ((intValue = inputBaseStream.ReadByte()) != -1)
    {
        unencryptStream.WriteByte((byte)intValue);
    }

    // Process is:
    //  inputBaseStream -> (encryptStream -> outputBaseStream)
}
Sub ReadShiftedFile()

    'Create the base streams for the input and output files
    Using inputBaseStream As FileStream = File.OpenRead("shifted.txt")
        Using outputBaseStream As FileStream = File.Open("unshifted.txt", FileMode.Create, FileAccess.Write)
            Using unencryptStream As CipherStream = CipherStream.CreateForWrite(outputBaseStream)


                'Read byte from inputBaseStream through the encryptStream (shifted bytes into normal bytes)
                Dim intValue As Integer = inputBaseStream.ReadByte()
                While intValue <> -1

                    unencryptStream.WriteByte(Convert.ToByte(intValue))

                    intValue = inputBaseStream.ReadByte()

                End While

            End Using
        End Using
    End Using

End Sub

Tenga en cuenta los siguientes aspectos sobre el código anterior:

  • Hay dos objetos FileStream:
    • El primer objeto FileStream (inputBaseStream variable) lee el contenido del archivo shifted.txt. Esta es la entrada de flujo de datos.
    • El segundo objeto FileStream (outputBaseStream variable) escribe datos entrantes en el archivo unshifted.txt. Esta es la salida de flujo de datos.
  • El objeto CipherStream ( variableunencryptStream ) encapsula el outputBaseStream, lo que outputBaseStream la secuencia base para unencryptStream.

Aquí, el código es ligeramente diferente del ejemplo anterior. En lugar de encapsular el flujo de entrada, unencryptStream encapsula el flujo de salida. A medida que los datos se leen desde inputBaseStream flujo de entrada, se envía al contenedor de flujo de salida unencryptStream. Cuando unencryptStream recibe datos, los transforma y, a continuación, escribe los datos en el flujo base outputBaseStream. El flujo de salida outputBaseStream escribe los datos en el archivo unshifted.txt.

Validación de los datos transformados

Los dos ejemplos anteriores realizaron dos operaciones en los datos. En primer lugar, el contenido del archivo data.txt se cifró y guardó en el archivo shifted.txt. Y, en segundo lugar, el contenido cifrado del archivo shifted.txt se descifra y se guardó en el archivo unshifted.txt. Por lo tanto, el archivo data.txt y unshifted.txt archivo deben ser exactamente iguales. En el código siguiente se comparan esos archivos por igualdad:

bool IsShiftedFileValid()
{
    // Read the shifted file
    string originalText = File.ReadAllText("data.txt");

    // Read the shifted file
    string shiftedText = File.ReadAllText("unshifted.txt");

    // Check if the decrypted file is valid
    return shiftedText == originalText;
}
Function IsShiftedFileValid() As Boolean

    'Read the shifted file
    Dim originalText As String = File.ReadAllText("data.txt")

    'Read the shifted file
    Dim shiftedText As String = File.ReadAllText("unshifted.txt")

    'Check if the decrypted file is valid
    Return shiftedText = originalText

End Function

El código siguiente ejecuta todo este proceso de cifrado y descifrado completo:

// Read the contents of data.txt, encrypt it, and write it to shifted.txt
WriteShiftedFile();

// Read the contents of shifted.txt, decrypt it, and write it to unshifted.txt
ReadShiftedFile();

// Check if the decrypted file is valid
Console.WriteLine(IsShiftedFileValid()
                    ? "Decrypted file is valid"     // True
                    : "Decrypted file is invalid"   // False
                 );

// Output:
//   Decrypted file is valid
Sub Main(args As String())
    'Read the contents of data.txt, encrypt it, And write it to shifted.txt
    WriteShiftedFile()

    'Read the contents of shifted.txt, decrypt it, And write it to unshifted.txt
    ReadShiftedFile()

    'Check if the decrypted file Is valid
    Console.WriteLine(IIf(IsShiftedFileValid(),
                            "Decrypted file is valid",  ' True
                            "Decrypted file is invalid" ' False
                     ))
End Sub

Clase CipherStream

El fragmento de código siguiente proporciona la clase CipherStream, que usa un cifrado de desplazamiento básico para cifrar y descifrar bytes. Esta clase hereda de Stream y admite la lectura o escritura de datos.

Advertencia

El cifrado usado en este ejemplo es básico y no seguro. No está diseñado para cifrar realmente los datos para su uso, pero se proporciona para demostrar la modificación de los datos a través de la composición del flujo.

using System.IO;

public class CipherStream : Stream
{
    // WARNING: This is a simple encoding algorithm and should not be used in production code

    const byte ENCODING_OFFSET = 80;

    private bool _readable;
    private bool _writable;

    private Stream _wrappedBaseStream;

    public override bool CanRead => _readable;
    public override bool CanSeek => false;
    public override bool CanWrite => _writable;
    public override long Length => _wrappedBaseStream.Length;
    public override long Position
    {
        get => _wrappedBaseStream.Position;
        set => _wrappedBaseStream.Position = value;
    }

    public static CipherStream CreateForRead(Stream baseStream)
    {
        return new CipherStream(baseStream)
        {
            _readable = true,
            _writable = false
        };
    }

    public static CipherStream CreateForWrite(Stream baseStream)
    {
        return new CipherStream(baseStream)
        {
            _readable = false,
            _writable = true
        };
    }

    private CipherStream(Stream baseStream) =>
        _wrappedBaseStream = baseStream;

    public override int Read(byte[] buffer, int offset, int count)
    {
        if (!_readable) throw new NotSupportedException();
        if (count == 0) return 0;

        int returnCounter = 0;

        for (int i = 0; i < count; i++)
        {
            int value = _wrappedBaseStream.ReadByte();

            if (value == -1)
                return returnCounter;

            value += ENCODING_OFFSET;
            if (value > byte.MaxValue)
                value -= byte.MaxValue;

            buffer[i + offset] = Convert.ToByte(value);
            returnCounter++;
        }

        return returnCounter;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        if (!_writable) throw new NotSupportedException();

        byte[] newBuffer = new byte[count];
        buffer.CopyTo(newBuffer, offset);

        for (int i = 0; i < count; i++)
        {
            int value = newBuffer[i];

            value -= ENCODING_OFFSET;

            if (value < 0)
                value = byte.MaxValue - value;

            newBuffer[i] = Convert.ToByte(value);
        }

        _wrappedBaseStream.Write(newBuffer, 0, count);
    }

    public override void Flush() => _wrappedBaseStream.Flush();
    public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
    public override void SetLength(long value) => throw new NotSupportedException();
}
Imports System.IO

Public Class CipherStream
    Inherits Stream

    Const ENCODING_OFFSET As Byte = 80

    Private _readable As Boolean = False
    Private _writable As Boolean = False

    Private _wrappedBaseStream As Stream

    Public Overrides ReadOnly Property CanRead As Boolean
        Get
            Return _readable
        End Get
    End Property

    Public Overrides ReadOnly Property CanSeek As Boolean
        Get
            Return False
        End Get
    End Property

    Public Overrides ReadOnly Property CanWrite As Boolean
        Get
            Return _writable
        End Get
    End Property

    Public Overrides ReadOnly Property Length As Long
        Get
            Return _wrappedBaseStream.Length
        End Get
    End Property

    Public Overrides Property Position As Long
        Get
            Return _wrappedBaseStream.Position
        End Get
        Set(value As Long)
            _wrappedBaseStream.Position = value
        End Set
    End Property

    Public Shared Function CreateForRead(baseStream As Stream) As CipherStream
        Return New CipherStream(baseStream) With
        {
            ._readable = True,
            ._writable = False
        }
    End Function

    Public Shared Function CreateForWrite(baseStream As Stream) As CipherStream
        Return New CipherStream(baseStream) With
        {
            ._readable = False,
            ._writable = True
        }
    End Function

    Private Sub New(baseStream As Stream)
        _wrappedBaseStream = baseStream
    End Sub

    Public Overrides Function Read(buffer() As Byte, offset As Integer, count As Integer) As Integer

        If Not _readable Then Throw New NotSupportedException()
        If count = 0 Then Return 0

        Dim returnCounter As Integer = 0

        For i = 0 To count - 1

            Dim value As Integer = _wrappedBaseStream.ReadByte()

            If (value = -1) Then Return returnCounter

            value += ENCODING_OFFSET
            If value > Byte.MaxValue Then
                value -= Byte.MaxValue
            End If

            buffer(i + offset) = Convert.ToByte(value)
            returnCounter += 1

        Next

        Return returnCounter

    End Function

    Public Overrides Sub Write(buffer() As Byte, offset As Integer, count As Integer)
        If Not _writable Then Throw New NotSupportedException()

        Dim newBuffer(count) As Byte
        buffer.CopyTo(newBuffer, offset)

        For i = 0 To count - 1

            Dim value As Integer = newBuffer(i)

            value -= ENCODING_OFFSET

            If value < 0 Then
                value = Byte.MaxValue - value
            End If

            newBuffer(i) = Convert.ToByte(value)

        Next

        _wrappedBaseStream.Write(newBuffer, 0, count)

    End Sub


    Public Overrides Sub Flush()
        _wrappedBaseStream.Flush()
    End Sub

    Public Overrides Function Seek(offset As Long, origin As SeekOrigin) As Long
        Throw New NotSupportedException()
    End Function

    Public Overrides Sub SetLength(value As Long)
        Throw New NotSupportedException()
    End Sub

End Class

Consulte también