Redigir fluxos
Um repositório de backup é uma mídia de armazenamento, como um disco ou uma memória. Cada tipo de repositório de backup implementa seu próprio fluxo como uma implementação da classe Stream.
Cada tipo de fluxo lê e grava bytes de e para seu repositório de backup específico. Os fluxos que se conectam aos repositórios de backup são chamados de fluxos base. Os fluxos base têm construtores com os parâmetros necessários para conectar o fluxo ao repositório de backup. Por exemplo, FileStream tem construtores que especificam um parâmetro de modo de acesso, que determina se o arquivo é lido, gravado ou ambos.
O design das classes System.IO fornece uma composição de fluxo simplificada. Você pode anexar os fluxos base a um ou mais fluxos de passagem que fornecem a funcionalidade desejada. Você pode anexar um leitor ou um gravador ao final da cadeia, de forma que os tipos preferidos possam ser lidos ou gravados com facilidade.
Pré-requisitos
Esses exemplos usam um arquivo de texto sem formatação chamado data.txt. Esse arquivo deve conter algum texto.
Exemplo: criptografar e descriptografar dados de fluxo
O exemplo a seguir lê dados de um arquivo, os criptografa e grava os dados criptografados em outro arquivo. A composição do fluxo é usada para transformar os dados usando uma criptografia básica de mudança. Cada byte que passa pelo fluxo tem seu valor alterado por 80.
Aviso
A criptografia usada neste exemplo é básica e não segura. Não se destina a criptografar dados para uso, mas é fornecida para demonstrar a alteração de dados por meio da composição do fluxo.
Ler os dados de origem para criptografia
O código a seguir lê o texto de um arquivo, o transforma e grava em outro arquivo.
Dica
Antes de examinar esse código, saiba que CipherStream
é um tipo definido pelo usuário. O código dessa classe é fornecido na seção classe 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
Considere os seguintes aspectos sobre o código anterior:
- Há dois objetos FileStream:
- O primeiro objeto
FileStream
(variávelinputBaseStream
) lê o conteúdo do arquivo data.txt. Esse é o fluxo de dados de entrada. - O segundo objeto
FileStream
(variáveloutputBaseStream
) grava dados de entrada no arquivo shifted.txt. Esse é o fluxo de dados de saída.
- O primeiro objeto
- O objeto
CipherStream
(variávelencryptStream
) encapsula oinputBaseStream
, tornandoinputBaseStream
o fluxo base paraencryptStream
.
O fluxo de entrada poderia ser lido diretamente, gravando os dados no fluxo de saída, mas isso não transformaria os dados. Em vez disso, o wrapper de fluxo de entrada encryptStream
é usado para ler os dados. À medida que os dados são lidos de encryptStream
, eles são retirados do fluxo base inputBaseStream
, os transformam e os retornam. Os dados retornados são gravados em outputBaseStream
, que grava os dados no arquivo shifted.txt.
Ler os dados transformados para descriptografia
Esse código inverte a criptografia executada pelo 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
Considere os seguintes aspectos sobre o código anterior:
- Há dois objetos FileStream:
- O primeiro objeto
FileStream
(variávelinputBaseStream
) lê o conteúdo do arquivo shifted.txt. Esse é o fluxo de dados de entrada. - O segundo objeto
FileStream
(variáveloutputBaseStream
) grava dados de entrada no arquivo unshifted.txt. Esse é o fluxo de dados de saída.
- O primeiro objeto
- O objeto
CipherStream
(variávelunencryptStream
) encapsula ooutputBaseStream
, tornandooutputBaseStream
o fluxo base paraunencryptStream
.
Aqui, o código é ligeiramente diferente do exemplo anterior. Em vez de encapsular o fluxo de entrada, unencryptStream
encapsula o fluxo de saída. À medida que os dados são lidos do fluxo de entrada inputBaseStream
, eles são enviados para o wrapper de fluxo de saída unencryptStream
. Quando unencryptStream
recebe dados, ele os transforma e grava no fluxo base outputBaseStream
. O fluxo de saída outputBaseStream
grava os dados no arquivo unshifted.txt.
Validar os dados transformados
Os dois exemplos anteriores executaram duas operações nos dados. Primeiro, o conteúdo do arquivo data.txt foi criptografado e salvo no arquivo shifted.txt. Em segundo lugar, o conteúdo criptografado do arquivo shifted.txt foi descriptografado e salvo no arquivo unshifted.txt. Portanto, o arquivo data.txt e o arquivo unshifted.txt devem ser exatamente iguais. O código a seguir compara esses arquivos quanto à igualdade:
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
O código a seguir executa todo esse processo de criptografar-descriptografar:
// 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
Classe CipherStream
O snippet a seguir fornece a classe CipherStream
, que usa uma criptografia básica de deslocamento para criptografar e descriptografar bytes. Essa classe herda de Stream e dá suporte à leitura ou gravação de dados.
Aviso
A criptografia usada neste exemplo é básica e não segura. Não se destina a criptografar dados para uso, mas é fornecida para demonstrar a alteração de dados por meio da composição do fluxo.
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