Создание потоков
Резервное хранилище — это устройство хранения информации, например диск или память. Каждый тип резервного хранилища реализует свой собственный поток в качестве реализации Stream класса.
Каждый тип потока считывает и записывает байты в собственное резервное хранилище. Потоки, которые связаны с резервными хранилищами, называются базовыми. Базовые потоки имеют конструкторы, которые используют параметры для подключения к соответствующему резервному хранилищу. Например, FileStream имеет конструкторы, указывающие параметр режима доступа, который определяет, считывается ли файл из файла, записывается в него или оба.
В структуре классов System.IO реализовано упрощенное составление потоков. Базовые потоки могут присоединяться к одному или нескольким транзитным потокам, которые предоставляют нужные возможности. Вы можете прикрепить в конце цепочки средство чтения или записи, что позволяет удобно читать и записывать нужные типы.
Необходимые компоненты
В этих примерах используется обычный текстовый файл с именем data.txt. Этот файл должен содержать текст.
Пример. Шифрование и расшифровка данных потока
Следующий пример считывает данные из файла, шифрует его, а затем записывает зашифрованные данные в другой файл. Композиция потоков используется для преобразования данных с помощью базового сдвига шифра. Каждый байт, проходящий через поток, имеет значение, измененное на 80.
Предупреждение
Шифрование, используемое в этом примере, является базовым и небезопасным. Он не предназначен для фактическиго шифрования данных для использования, но предоставляется для демонстрации изменения данных через состав потока.
Чтение исходных данных для шифрования
Следующий код считывает текст из одного файла, преобразует его, а затем записывает его в другой файл.
Совет
Прежде чем просматривать этот код, знают, что CipherStream
это определяемый пользователем тип. Код этого класса представлен в разделе класса 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
Рассмотрим следующие аспекты предыдущего кода:
- Существует два FileStream объекта:
FileStream
Первый объект (inputBaseStream
переменная) считывает содержимое файла data.txt. Это поток входных данных.FileStream
Второй (outputBaseStream
переменная) объект записывает входящие данные в файл shifted.txt. Это поток выходных данных.
- Объект
CipherStream
(encryptStream
переменная) заключаетinputBaseStream
в себя оболочку, делаяinputBaseStream
базовый поток дляencryptStream
.
Входной поток можно считывать напрямую, записывая данные в выходной поток, но это не преобразовывает данные. Вместо этого encryptStream
для чтения данных используется оболочка входного потока. По мере считывания encryptStream
данных он извлекается из inputBaseStream
базового потока, преобразует его и возвращает его. Возвращенные данные записываются outputBaseStream
в файл, который записывает данные в файл shifted.txt .
Чтение преобразованных данных для расшифровки
Этот код изменяет шифрование, выполняемого предыдущим кодом:
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
Рассмотрим следующие аспекты предыдущего кода:
- Существует два FileStream объекта:
FileStream
Первый объект (inputBaseStream
переменная) считывает содержимое файла shifted.txt. Это поток входных данных.FileStream
Второй (outputBaseStream
переменная) объект записывает входящие данные в файл unshifted.txt. Это поток выходных данных.
- Объект
CipherStream
(unencryptStream
переменная) заключаетoutputBaseStream
в себя оболочку, делаяoutputBaseStream
базовый поток дляunencryptStream
.
Здесь код немного отличается от предыдущего примера. Вместо упаковки входного потока unencryptStream
упаковывает выходной поток. Так как данные считываются из inputBaseStream
входного потока, он отправляется в оболочку выходного unencryptStream
потока. При unencryptStream
получении данных он преобразует его, а затем записывает данные в базовый outputBaseStream
поток. Выходной outputBaseStream
поток записывает данные в файл unshifted.txt .
Проверка преобразованных данных
Два предыдущих примера выполнили две операции с данными. Во-первых, содержимое файла data.txt было зашифровано и сохранено в файле shifted.txt . Во-вторых, зашифрованное содержимое файла shifted.txt было расшифровывается и сохраняется в файле unshifted.txt . Поэтому файл data.txt и файл unshifted.txt должны совпадать. Следующий код сравнивает эти файлы с равенством:
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
Следующий код выполняет весь процесс расшифровки шифрования:
// 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
Следующий фрагмент кода предоставляет CipherStream
класс, который использует базовый шифр переключения для шифрования и расшифровки байтов. Этот класс наследует от Stream и поддерживает чтение или запись данных.
Предупреждение
Шифрование, используемое в этом примере, является базовым и небезопасным. Он не предназначен для фактическиго шифрования данных для использования, но предоставляется для демонстрации изменения данных через состав потока.
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