Возможно ли base64-кодировать файл в кусках?
Я пытаюсь base64 кодировать огромный входной файл и заканчивать текстовым выходным файлом, и я пытаюсь выяснить, возможно ли кодировать входной файл побито, или мне нужно закодируйте всю вещь сразу.
Это будет сделано в AS/400 (iSeries), если это имеет значение. Я использую свою собственную процедуру кодирования base64 (написанную в RPG), которая отлично работает и, если бы это был не случай ограничений по размеру, было бы хорошо.
Ответы
Ответ 1
Невозможно побитовое, но 3 байта за раз, или кратные 3 байта в момент времени будут!.
Другими словами, если вы разделите свой входной файл на "куски", размер которого (являются) кратными 3 байтам, вы можете закодировать куски отдельно и объединить полученные в результате фрагменты, закодированные в B64 (в соответствующем orde, конечно. Обратите внимание, что последний chuink не должен быть точно кратным 3 байтам в зависимости от значения по модулю 3 его соответствующего значения B64 будет иметь несколько из этих дополняющих символов (как правило, знак равенства) но это нормально, так как это будет единственный кусок, который имеет (и нуждается) такое дополнение.
В направлении декодирования это та же идея, за исключением того, что вам нужно разбить данные, закодированные в B64, в кратном размере 4 байта. Декодируйте их параллельно/индивидуально по желанию и перекомпоновите исходные данные, добавив декодированные части вместе (снова в том же порядке).
Пример:
Содержимое "Файл" =
"Never argue with the data." (Jimmy Neutron)
.
Прямое кодирование = Ik5ldmVyIGFyZ3VlIHdpdGggdGhlIGRhdGEuIiAoSmltbXkgTmV1dHJvbik=
Теперь, в кусках:
"Never argue
→ Ik5ldmVyIGFyZ3Vl
with the
→ IHdpdGggdGhl
data." (Jimmy Neutron)
→ IGRhdGEuIiAoSmltbXkgTmV1dHJvbik=
Как вы видите фрагмент в этом порядке, 3 кодированных фрагмента совпадают с кодом, созданным для всего файла.
Декодирование выполняется аналогичным образом с произвольным размером chuncked при условии, что они кратны 4 байтам. Абсолютно не нужно иметь никакого соответствия между размерами, используемыми для кодирования. (хотя стандартизация до одного размера для каждого направления (скажем, 300 и 400) может сделать вещи более однородными и удобными в управлении.
Ответ 2
Хммм, если вы сами написали преобразование base64, вы должны были заметить очевидную вещь: каждая последовательность из 3 октетов представлена 4 символами в base64.
Таким образом, вы можете разделить данные base64 на каждый кратный четыре символа, и будет возможно преобразовать эти куски обратно в исходные биты.
Я не знаю, как файлы символов и байтовые файлы обрабатываются в AS/400, но если у них есть обе концепции, это должно быть очень просто.
- - текстовые файлы, ограниченные длиной каждой строки?
- являются текстовыми файлами, ориентированными на линию, или они являются просто символьными потоками?
- Сколько битов имеет один байт?
- - это байтовые файлы, дополненные в конце, так что можно создавать только файлы, которые охватывают целые сектора диска.
Если вы можете ответить на все эти вопросы, какие точные трудности у вас остались?
Ответ 3
Это тривиальное усилие разбивать любой заданный поток на куски.
Вы можете без проблем использовать base64 любой фрагмент байтов.
Проблема, с которой вы столкнулись, заключается в том, что, если вы не зададите конкретные требования к вашим кускам (кратные 3 байтам), последовательность блоков с кодировкой base64 будет отличаться от того, какой вы хотите.
В С# это один (неряшливый) способ сделать это лениво. Выполнение фактически отложено до тех пор, пока не будет выведена строка. Concat вызывается, поэтому вы можете делать все, что хотите, с чередующимися строками. (Если вы подключите это в LINQPad, вы увидите вывод)
void Main()
{
var data = "lorum ipsum etc lol this is an example!!";
var bytes = Encoding.ASCII.GetBytes(data);
var testFinal = Convert.ToBase64String(bytes);
var chunkedBytes = bytes.Chunk(3);
var base64chunks = chunkedBytes.Select(i => Convert.ToBase64String(i.ToArray()));
var final = string.Concat(base64chunks);
testFinal.Dump(); //output
final.Dump(); //output
}
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> list, int chunkSize)
{
while(list.Take(1).Count() > 0)
{
yield return list.Take(chunkSize);
list = list.Skip(chunkSize);
}
}
}
Выход
bG9ydW0gaXBzdW0gZXRjIGxvbCB0aGlzIGlzIGFuIGV4YW1wbGUhIQ==
bG9ydW0gaXBzdW0gZXRjIGxvbCB0aGlzIGlzIGFuIGV4YW1wbGUhIQ==