Vytváření datových proudů
Záložní úložiště je úložné médium, například disk nebo paměť. Každý typ záložního úložiště implementuje vlastní datový proud jako implementaci Stream třídy.
Každý typ datového proudu čte a zapisuje bajty z a do příslušného záložního úložiště. Datové proudy, které se připojují k záložním úložištím, se nazývají základní datové proudy. Základní datové proudy mají konstruktory s parametry nezbytnými pro připojení datového proudu k záložnímu úložišti. Má například FileStream konstruktory, které určují parametr režimu přístupu, který určuje, jestli se soubor načítá, zapisuje do nebo do obou.
Návrh tříd poskytuje zjednodušené složení datových System.IO proudů. Základní streamy můžete připojit k jednomu nebo několika průchozím datovým proudům, které poskytují požadované funkce. Ke konci řetězce můžete připojit čtečku nebo zapisovač, takže upřednostňované typy lze snadno číst nebo zapisovat.
Požadavky
Tyto příklady používají soubor prostého textu s názvem data.txt. Tento soubor by měl obsahovat nějaký text.
Příklad: Šifrování a dešifrování dat datového proudu
Následující příklad načte data ze souboru, zašifruje je a pak zapíše zašifrovaná data do jiného souboru. Složení datového proudu slouží k transformaci dat pomocí základní šifry posunu. Každý bajt, který prochází proudem, má svou hodnotu změněnou o 80.
Upozorňující
Šifrování použité v tomto příkladu je základní a nezabezpečené. Účelem není skutečně šifrovat data pro použití, ale poskytuje se k předvedení změn dat prostřednictvím složení datového proudu.
Čtení zdrojových dat pro šifrování
Následující kód přečte text z jednoho souboru, transformuje ho a pak ho zapíše do jiného souboru.
Tip
Než si tento kód prohlédnete, víme, že CipherStream
se jedná o uživatelem definovaný typ. Kód pro tuto třídu je poskytován v části CipherStream třídy .
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
Zvažte následující aspekty předchozího kódu:
- Existují dva FileStream objekty:
- První
FileStream
(inputBaseStream
proměnná) objekt přečte obsah souboru data.txt . Toto je vstupní datový proud. - Druhý
FileStream
(outputBaseStream
proměnný) objekt zapisuje příchozí data do shifted.txt souboru. Toto je výstupní datový proud.
- První
- Objekt
CipherStream
(encryptStream
proměnná) zabalíinputBaseStream
objekt , který vytváříinputBaseStream
základní datový proud proencryptStream
.
Vstupní datový proud je možné číst přímo, zapisovat data do výstupního datového proudu, ale tím by se data ne transformovala. Místo toho se ke čtení dat používá obálka encryptStream
vstupního datového proudu. Při čtení encryptStream
dat se data načítají ze základního datového inputBaseStream
proudu, transformují je a vrací. Vrácená data se zapisují do outputBaseStream
souboru shifted.txt .
Čtení transformovaných dat pro dešifrování
Tento kód obrátí šifrování provedené předchozím kódem:
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
Zvažte následující aspekty předchozího kódu:
- Existují dva FileStream objekty:
- První
FileStream
(inputBaseStream
proměnná) objekt přečte obsah souboru shifted.txt . Toto je vstupní datový proud. - Druhý
FileStream
(outputBaseStream
proměnný) objekt zapisuje příchozí data do unshifted.txt souboru. Toto je výstupní datový proud.
- První
- Objekt
CipherStream
(unencryptStream
proměnná) zabalíoutputBaseStream
objekt , který vytváříoutputBaseStream
základní datový proud prounencryptStream
.
Tady se kód mírně liší od předchozího příkladu. Místo zabalení vstupního datového proudu unencryptStream
zabalí výstupní datový proud. Vzhledem k tomu, že se data čtou ze inputBaseStream
vstupního datového proudu, odesílají se do obálky výstupního datového unencryptStream
proudu. Když unencryptStream
přijímá data, transformuje je a zapíše je do základního datového outputBaseStream
proudu. Výstupní outputBaseStream
datový proud zapisuje data do souboru unshifted.txt .
Ověření transformovaných dat
Dva předchozí příklady prováděly dvě operace s daty. Nejprve se obsah souboru data.txt zašifroval a uložil do souboru shifted.txt . Za druhé, šifrovaný obsah souboru shifted.txt byl dešifrován a uložen do unshifted.txt souboru. Proto by soubor data.txt a unshifted.txt měl být úplně stejný. Následující kód porovnává tyto soubory pro rovnost:
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
Následující kód spustí celý proces šifrování a dešifrování:
// 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 – třída
Následující fragment kódu poskytuje CipherStream
třídu, která používá základní posun šifry k šifrování a dešifrování bajtů. Tato třída dědí data a Stream podporuje čtení nebo zápis dat.
Upozorňující
Šifrování použité v tomto příkladu je základní a nezabezpečené. Účelem není skutečně šifrovat data pro použití, ale poskytuje se k předvedení změn dat prostřednictvím složení datového proudu.
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