Delen via


Stromen opstellen

Een back-uparchief is een opslagmedium, zoals een schijf of geheugen. Elk type back-uparchief implementeert een eigen stream als een implementatie van de Stream klasse.

Elk stroomtype leest en schrijft bytes van en naar de opgegeven back-upopslag. Streams die verbinding maken met back-uparchieven, worden basisstreams genoemd. Basisstromen hebben constructors met de parameters die nodig zijn om de stream te verbinden met het backing-archief. Heeft bijvoorbeeld FileStream constructors die een parameter voor de toegangsmodus opgeven, die bepaalt of het bestand wordt gelezen, geschreven naar of beide.

Het ontwerp van de System.IO klassen biedt vereenvoudigde stroomsamenstelling. U kunt basisstreams koppelen aan een of meer passthrough-streams die de gewenste functionaliteit bieden. U kunt een lezer of schrijver toevoegen aan het einde van de keten, zodat de voorkeurstypen eenvoudig kunnen worden gelezen of geschreven.

Vereisten

In deze voorbeelden wordt een bestand met tekst zonder opmaak met de naam data.txt gebruikt. Dit bestand moet tekst bevatten.

Voorbeeld: Streamgegevens versleutelen en ontsleutelen

In het volgende voorbeeld worden gegevens uit een bestand gelezen, versleuteld en worden de versleutelde gegevens vervolgens naar een ander bestand geschreven. Streamsamenstelling wordt gebruikt om de gegevens te transformeren met behulp van een eenvoudige verschuivingscodering. Elke byte die door de stream wordt doorgegeven, heeft de waarde ervan met 80 gewijzigd.

Waarschuwing

De versleuteling die in dit voorbeeld wordt gebruikt, is eenvoudig en onbeveiligd. Het is niet bedoeld om gegevens daadwerkelijk te versleutelen voor gebruik, maar wordt geleverd om het wijzigen van gegevens te demonstreren via stroomsamenstelling.

De brongegevens voor versleuteling lezen

Met de volgende code wordt de tekst uit het ene bestand gelezen, getransformeerd en vervolgens naar een ander bestand geschreven.

Tip

Voordat u deze code bekijkt, moet u weten dat het een door de CipherStream gebruiker gedefinieerd type is. De code voor deze klasse wordt opgegeven in de sectie CipherStream-klasse .

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

Houd rekening met de volgende aspecten van de vorige code:

  • Er zijn twee FileStream objecten:
    • Het eerste FileStream object (inputBaseStream variabele) leest de inhoud van het data.txt-bestand . Dit is de invoergegevensstroom .
    • Het tweede FileStream object (outputBaseStream variabele) schrijft binnenkomende gegevens naar het shifted.txt-bestand . Dit is de uitvoergegevensstroom .
  • Het CipherStream object (encryptStream variabele) verpakt het inputBaseStream, waardoor inputBaseStream de basisstroom voor encryptStream.

De invoerstroom kan rechtstreeks worden gelezen en de gegevens naar de uitvoerstroom worden geschreven, maar dat zou de gegevens niet transformeren. In plaats daarvan wordt de encryptStream invoerstroom-wrapper gebruikt om de gegevens te lezen. Naarmate de gegevens worden gelezen encryptStream, worden deze opgehaald uit de inputBaseStream basisstroom, getransformeerd en geretourneerd. De geretourneerde gegevens worden naar outputBaseStreamhet shifted.txt-bestand geschreven.

De getransformeerde gegevens voor ontsleuteling lezen

Met deze code wordt de versleuteling omgekeerd die door de vorige code wordt uitgevoerd:

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

Houd rekening met de volgende aspecten van de vorige code:

  • Er zijn twee FileStream objecten:
    • Het eerste FileStream object (inputBaseStream variabele) leest de inhoud van het shifted.txt-bestand . Dit is de invoergegevensstroom .
    • Het tweede FileStream object (outputBaseStream variabele) schrijft binnenkomende gegevens naar het unshifted.txt-bestand . Dit is de uitvoergegevensstroom .
  • Het CipherStream object (unencryptStream variabele) verpakt het outputBaseStream, waardoor outputBaseStream de basisstroom voor unencryptStream.

Hier verschilt de code enigszins van het vorige voorbeeld. In plaats van de invoerstroom te verpakken, unencryptStream verpakt u de uitvoerstroom. Terwijl de gegevens uit inputBaseStream de invoerstroom worden gelezen, worden deze verzonden naar de unencryptStream uitvoerstroom-wrapper. Wanneer unencryptStream gegevens worden ontvangen, worden deze getransformeerd en worden de gegevens vervolgens naar de outputBaseStream basisstroom geschreven. De outputBaseStream uitvoerstroom schrijft de gegevens naar het unshifted.txt-bestand .

De getransformeerde gegevens valideren

In de twee vorige voorbeelden zijn twee bewerkingen op de gegevens uitgevoerd. Eerst is de inhoud van het data.txt-bestand versleuteld en opgeslagen in het shifted.txt-bestand . En ten tweede werd de versleutelde inhoud van het shifted.txt-bestand ontsleuteld en opgeslagen in het unshifted.txt-bestand . Daarom moeten het data.txt - en unshifted.txt-bestand precies hetzelfde zijn. De volgende code vergelijkt deze bestanden voor gelijkheid:

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

Met de volgende code wordt dit volledige versleutelingsproces uitgevoerd:

// 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

CipherStream-klasse

Het volgende codefragment biedt de CipherStream klasse, die gebruikmaakt van een eenvoudige verschuiving van codering voor het versleutelen en ontsleutelen van bytes. Deze klasse neemt gegevens over van Stream en ondersteunt het lezen of schrijven van gegevens.

Waarschuwing

De versleuteling die in dit voorbeeld wordt gebruikt, is eenvoudig en onbeveiligd. Het is niet bedoeld om gegevens daadwerkelijk te versleutelen voor gebruik, maar wordt geleverd om het wijzigen van gegevens te demonstreren via stroomsamenstelling.

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

Zie ook