Я решил попробовать разобрать PDF-файл средствами c# и у меня возник вопрос. Вопрос, наверное, больше про байты, чем про сам формат, но если вы работали над подобной задачей, то будет просто отлично.
Для начала, я создал в Word'e самый простой документ с текстом "test" и сохранил его в формате PDF. Исходя из спецификации, в самом начале мне нужно прочитать число из предпоследней строки (это количество байтов от начала документа, до определённого блока).
Для наглядности, если открыть файл pdf в VisualStudio, то можно увидеть текст вида:
какой-то текст
ещё текст
много текста
ТУТ ЧИСЛО БАЙТОВ
%%EOF
То есть, по логике, чтобы прочитать это число, мне нужно отступить от конца файла 11 байтов (5 байтов последней строки + 2 байта \r\n + 4 байта Int32). Я пробовал отступать и 10, и 12, и еще очень большой диапазон байтов, но считывается не то число, которое ожидалось (считывал функцией BinaryReader.ReadInt32). Если считывать как символы или строку(BinaryReader.ReadChars(n)), то считывается нормально.
Тут я начал подозревать, что pdf-файлик то не совсем двоичный, а это число вовсе не число, а текст. Открыл его в hex editor, содержимое было было таким (показан лишь конец):
То есть, мы видим, что "число" занимает 5 байтов. Выходит, что оно действительно записано в виде текста. Вопросы:
P.S. Я преследую исключительно научный интерес, не нужно советовать библиотеки по работе с pdf.
Правильно ли все вышенаписанное?
В целом, да, но далеко не все. А именно:
Тут я начал подозревать, что pdf-файлик то не совсем двоичный, а это число вовсе не число, а текст.
Все файлы по сути бинарные (двоичные). То, что в нем можно увидеть строку не отменяет того факта, что он бинарный. Бинарный файл - это последовательность байтов. Строка - тоже последовательность байтов. Важно лишь то, каким образом с ней работать: как со строкой, как с массивом байтов, как с числом определенной разрядности и т.д.
В бинарный файл можно записывать и строку, и отдельно символ, и число, и др. (если вы работали с BinaryReader и BinaryWriter, то должны были это понять, потому что для разных типов данных есть разные методы для чтения/записи). Главное, чтобы человек, который будет писать код для чтения этого файла, понимал, где записана строка, где число.
Как мне тогда правельнее считывать это число, ведь разрядов (соответственно и байтов) может быть разное количество и придётся как-то подбирать сдвиг с конца для FileStream?
Я сам не работал с чтением pdf-файла вручную, но, судя по спецификации, вам необходимо читать этот файл как текстовый (по крайней мере, trailer-часть). Можно воспользоваться методом File.ReadAllLines Получаете предпоследнюю строку в массиве и преобразуете ее в число (желательно, в UInt64).
Если хочется все-же как бинарный файл прочитать, то тогда нужно найти вторую с конца последовательность байт 0D 0A
и прочитать последовательность символов, начиная со следующего символа после второго 0D 0A
и заканчивая символом, предшествующим последнее OD OA
. Из вашего примера:
... 0D 0A 32 38 34 30 0D 0A ...
Будет прочитано 4 символа. Либо прочитать их как массив байт (BinaryReader.ReadBytes) и затем преобразовать с помощью метода System.Text.Encoding.ASCII.GetString (либо UTF8.GetString, я точно не могу сказать, как правильней).
Считываем 30 последних байтов, получаем строку между последними двумя \n. Это и есть наше число.
static int readLastNumber(FileStream fstream)
{
byte[] data = new byte[30];
fstream.Seek(-data.Length, SeekOrigin.End);
fstream.Read(data, 0, data.Length);
// Индексы начала и конца числа
int startPoint, endPoint;
int i = data.Length - 1;
if (data[i] == '\n')
i--;
while (data[i] != '\n')
i--;
endPoint = --i;
while (data[i] != '\n')
i--;
startPoint = ++i;
string number = Encoding.ASCII.GetString(data, startPoint, endPoint - startPoint);
return int.Parse(number);
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть программа на паскале, написанная изначально не мнойПеревожу ее на C#
Всем привет! Нужно, чтобы cmdexe открывался по пути "{Системный диск}\Windows\System32"
Не выходит исправить ошибку 2 errors were found during analysis