Skapa strömmar
Ett lagringslager är ett lagringsmedium, till exempel en disk eller ett minne. Varje typ av stödarkiv implementerar sin egen ström som en implementering av Stream klassen.
Varje strömtyp läser och skriver byte från och till dess angivna lagringsplats. Strömmar som ansluter till lagringsplatser kallas för basströmmar. Basströmmar har konstruktorer med de parametrar som krävs för att ansluta strömmen till lagringsplatsen. Till exempel FileStream har konstruktorer som anger en parameter för åtkomstläge, som avgör om filen läss från, skrivs till eller båda.
Klassernas System.IO design ger förenklad strömsammansättning. Du kan koppla basströmmar till en eller flera direktströmmar som tillhandahåller de funktioner du vill ha. Du kan koppla en läsare eller skrivare till slutet av kedjan, så att de önskade typerna enkelt kan läsas eller skrivas.
Förutsättningar
I de här exemplen används en oformaterad textfil med namnet data.txt. Den här filen bör innehålla text.
Exempel: Kryptera och dekryptera dataström
I följande exempel läss data från en fil, krypteras och de krypterade data skrivs sedan till en annan fil. Stream-komposition används för att transformera data med hjälp av ett grundläggande växlingskryptering. Varje byte som passerar genom dataströmmen får sitt värde ändrat med 80.
Varning
Krypteringen som används i det här exemplet är grundläggande och osäker. Det är inte avsett att faktiskt kryptera data för användning, men tillhandahålls för att demonstrera ändring av data via strömsammansättning.
Läsa källdata för kryptering
Följande kod läser texten från en fil, transformerar den och skriver den sedan till en annan fil.
Dricks
Innan du granskar den här koden bör du känna till att den CipherStream
är en användardefinierad typ. Koden för den här klassen finns i avsnittet CipherStream-klass .
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
Tänk på följande aspekter om den tidigare koden:
- Det finns två FileStream objekt:
- Det första
FileStream
objektet (inputBaseStream
variabeln) läser innehållet i filen data.txt . Det här är dataströmmen för indata . - Det andra
FileStream
objektet (outputBaseStream
variabeln) skriver inkommande data till shifted.txt-filen. Det här är utdataströmmen .
- Det första
- Objektet
CipherStream
(encryptStream
variabeln) omsluterinputBaseStream
, vilket görinputBaseStream
basströmmen förencryptStream
.
Indataströmmen kan läsas direkt och skriva data till utdataströmmen, men det skulle inte transformera data. encryptStream
I stället används indataströmomslutningen för att läsa data. När data läse från encryptStream
hämtas de inputBaseStream
från basströmmen, transformerar dem och returnerar dem. De returnerade data skrivs till outputBaseStream
, som skriver data till shifted.txt-filen.
Läsa transformerade data för dekryptering
Den här koden återställer krypteringen som utfördes av föregående kod:
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
Tänk på följande aspekter om den tidigare koden:
- Det finns två FileStream objekt:
- Det första
FileStream
objektet (inputBaseStream
variabeln) läser innehållet i shifted.txt-filen. Det här är dataströmmen för indata . - Det andra
FileStream
objektet (outputBaseStream
variabeln) skriver inkommande data till unshifted.txt-filen. Det här är utdataströmmen .
- Det första
- Objektet
CipherStream
(unencryptStream
variabeln) omsluteroutputBaseStream
, vilket göroutputBaseStream
basströmmen förunencryptStream
.
Här skiljer sig koden något från föregående exempel. I stället för att omsluta indataströmmen omsluter unencryptStream
du utdataströmmen. När data läse från inputBaseStream
indataströmmen skickas de till utdataströmsomslutningen unencryptStream
. När unencryptStream
du tar emot data transformeras de och skriver sedan data till outputBaseStream
basströmmen. Utdataströmmen outputBaseStream
skriver data till unshifted.txt-filen.
Verifiera transformerade data
De två föregående exemplen utförde två åtgärder på data. Först krypterades innehållet i data.txt-filen och sparades i filen shifted.txt. Och för det andra dekrypterades det krypterade innehållet i shifted.txt-filen och sparades i filen unshifted.txt. Därför bör data.txt-filen och unshifted.txt filen vara exakt samma. Följande kod jämför dessa filer för likhet:
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
Följande kod kör hela krypteringsdekrypteringsprocessen:
// 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-klass
Följande kodfragment innehåller CipherStream
klassen, som använder ett grundläggande växlings chiffer för att kryptera och dekryptera byte. Den här klassen ärver från Stream och stöder antingen läsning eller skrivning av data.
Varning
Krypteringen som används i det här exemplet är grundläggande och osäker. Det är inte avsett att faktiskt kryptera data för användning, men tillhandahålls för att demonstrera ändring av data via strömsammansättning.
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