Честно говоря, я не совсем понял, в чём состоит проблема. Если файл не слишком большой, то можно прочитать его в память при помощи File.ReadAllText, затем закодировать содержимое и записать в другой файл. Если файл большой, то можно использовать FileStream - логика немного меняется, но тоже ничего сложного.
Я немного оптимизировал Ваш код для строк:
class Crypto2
{
private readonly int[] _key;
private readonly int[] _inversedKey;
public Crypto2(string key)
{
var indexPairs = key
.Select((chr, idx1) => new { chr, idx1 }) // присваиваем каждому символу индекс
.OrderBy(arg => arg.chr) // сортируем по символам
.Select((arg, idx2) => new { arg.idx1, idx2 }) // и теперь создаём массив из пар "первоначальный индекс" <=> "отсортированный индекс".
.ToArray();
// Генерируем прямой ключ: чем "меньше" символ (в алфавитном порядке), тем меньше его индекс в конечном массиве.
// "а" => 0, ... , "ь" => 5
// Получаем: "цезарь" => [4, 1, 2, 0, 3, 5]
_key = indexPairs
.OrderBy(arg => arg.idx1)
.Select(arg => arg.idx2)
.ToArray();
// Обратная операция для декодирования
_inversedKey = indexPairs
.OrderBy(arg => arg.idx2)
.Select(arg => arg.idx1)
.ToArray();
}
public string Encrypt(string message)
{
return EncryptDecrypt(message, _key);
}
public string Decrypt(string message)
{
return EncryptDecrypt(message, _inversedKey);
}
private static string EncryptDecrypt(string message, int[] key)
{
var keyLength = key.Length;
var messageLength = message.Length;
if (messageLength % keyLength > 0)
{
// Дополняем строку пробелами, если необходимо
message = message.PadRight(messageLength + keyLength - messageLength % keyLength, ' ');
}
// Никогда не используйте конкатенацию строк в цикле (типа result += keyValuePairs[editKey[j]][i].ToString();). Это очень медленно.
// Для этих целей есть специальный класс StringBuilder.
// Мы заранее знаем длину конечной строки, поэтому инициализируем StringBuilder правильно.
var sb = new StringBuilder(messageLength) {Length = message.Length};
for (var i = 0; i < message.Length; i++)
{
// Вычисляем конечный индекс для вставки символа.
// Первая часть выражения "i / keyLength * keyLength" - округление i вниз до ближайшего значения, делящегося на keyLength
// Вторая часть "key[i % keyLength]" - вычисление новой позиции символа на основе ключа.
var idx = i / keyLength * keyLength + key[i % keyLength];
sb[idx] = message[i];
}
return sb.ToString();
}
}
А вот тот же код для файлов:
class Crypto3
{
private readonly int[] _key;
private readonly int[] _inversedKey;
public Crypto3(string key)
{
var indexPairs = key
.Select((chr, idx1) => new {chr, idx1})
.OrderBy(arg => arg.chr)
.Select((arg, idx2) =>
new
{
arg.idx1, idx2
})
.ToArray();
_key = indexPairs
.OrderBy(arg => arg.idx1)
.Select(arg => arg.idx2)
.ToArray();
_inversedKey = indexPairs
.OrderBy(arg => arg.idx2)
.Select(arg => arg.idx1)
.ToArray();
}
public void Encrypt(string sourceFile, string destinationFile)
{
EncryptDecrypt(sourceFile, destinationFile, _key);
}
public void Decrypt(string sourceFile, string destinationFile)
{
EncryptDecrypt(sourceFile, destinationFile, _inversedKey);
}
private static void EncryptDecrypt(string sourceFile, string destinationFile, int[] key)
{
var keyLength = key.Length;
var buffer1 = new byte[keyLength];
var buffer2 = new byte[keyLength];
using (var source = new FileStream(sourceFile, FileMode.Open))
using (var destination = new FileStream(destinationFile, FileMode.OpenOrCreate))
{
while (true)
{
var read = source.Read(buffer1, 0, keyLength);
if (read == 0)
{
return;
}
else if (read < keyLength)
{
for (int i = read; i < keyLength; i++)
{
buffer1[i] = (byte) ' ';
}
}
for (var i = 0; i < keyLength; i++)
{
var idx = i / keyLength * keyLength + key[i % keyLength];
buffer2[idx] = buffer1[i];
}
destination.Write(buffer2, 0, keyLength);
}
}
}
}