Как отправить бинарный файл

Обновлено: 07.07.2024

Двоичный файл является компьютерным файлом , который не является текстовым файлом . [1] Термин «двоичный файл» часто используется как термин, означающий «нетекстовый файл». [2] Многие форматы двоичных файлов содержат части, которые можно интерпретировать как текст; например, некоторые файлы компьютерных документов, содержащие форматированный текст , такие как старые файлы документов Microsoft Word , содержат текст документа, но также содержат информацию о форматировании в двоичной форме. [2]

Шестнадцатеричный дамп из 318 байтов Википедии фавиконки , или . В первом столбце указан начальный адрес строки, а в столбце * указано повторение.

Двоичные файлы обычно представляют собой последовательность байтов , что означает, что двоичные цифры ( биты ) сгруппированы по восьмеркам. Двоичные файлы обычно содержат байты, которые предназначены для интерпретации не как текстовые символы . Скомпилированные компьютерные программы являются типичными примерами; действительно, скомпилированные приложения иногда называются, особенно программистами, двоичными файлами . Но двоичные файлы также могут означать, что они содержат изображения, звуки, сжатые версии других файлов и т. Д. - короче говоря, любой тип содержимого файла вообще. [1]

Некоторые двоичные файлы содержат заголовки , блоки метаданных, используемые компьютерной программой для интерпретации данных в файле. Заголовок часто содержит подпись или магический номер, который может идентифицировать формат. Например, файл GIF может содержать несколько изображений, а заголовки используются для идентификации и описания каждого блока данных изображения. Начальные байты заголовка будут содержать текст, подобный GIF87a или GIF89a который может идентифицировать двоичный файл как файл GIF . Если двоичный файл не содержит заголовков, его можно назвать плоским двоичным файлом .

Чтобы отправлять двоичные файлы через определенные системы (например, электронную почту ), которые не допускают всех значений данных, они часто переводятся в простое текстовое представление (с использованием, например, Base64 ). Недостатком кодирования данных является увеличение размера файла во время передачи (например, использование Base64 увеличит размер файла примерно на 30%), а также необходимость перевода обратно в двоичный код после получения. Увеличенному размеру может противодействовать сжатие ссылок более низкого уровня, так как полученные текстовые данные будут иметь примерно столько же меньшей энтропии, сколько и увеличенный размер, поэтому фактические данные, передаваемые в этом сценарии, вероятно, будут очень близки к размеру оригинала. двоичные данные. См. Раздел « Двоичное кодирование текста» для получения дополнительной информации по этому вопросу.

Microsoft Windows и ее стандартные библиотеки для языков программирования C и C ++ позволяют программисту указывать параметр, указывающий, должен ли файл быть простым текстовым или двоичным при открытии файла; это влияет на вызовы стандартной библиотеки для чтения и записи из файла, поскольку система преобразует между символом «конца строки» C / C ++ (символ перевода строки ASCII) и последовательностью конца строки, которую Windows ожидает в файлах (код ASCII возврат каретки и перевод строки символов в последовательности). В Unix-подобных системах стандартные библиотеки C и C ++ в этих системах также позволяют программисту указать, должен ли файл быть текстовым или двоичным, но библиотеки могут игнорировать и игнорируют этот параметр как последовательность конца строки. в Unix-подобных системах - это просто символ конца строки C / C ++.

Редактор шестнадцатеричного или зритель может быть использован для данных просмотра файла в виде последовательности шестнадцатеричного (или десятичного, двоичный или ASCII символа) значений для соответствующих байт двоичного файла. [2]

Если двоичный файл открывается в текстовом редакторе , каждая группа из восьми битов обычно переводится как один символ, и пользователь будет видеть (возможно, неразборчивое) отображение текстовых символов. Если файл открыт в каком-то другом приложении, это приложение будет использовать каждый байт по-своему: возможно, приложение будет рассматривать каждый байт как число и выводить поток чисел от 0 до 255 - или, возможно, интерпретировать числа в байтах. как цвета и отображать соответствующее изображение. Другие типы средств просмотра (называемые «экстракторами слов») просто заменяют непечатаемые символы пробелами, открывая только читаемый человеком текст. Этот тип просмотра полезен для быстрой проверки двоичного файла, чтобы найти пароли в играх, найти скрытый текст в нетекстовых файлах и восстановить поврежденные документы. [2] Его даже можно использовать для проверки подозрительных файлов (программного обеспечения) на предмет нежелательных эффектов. Например, пользователь увидит любой URL / адрес электронной почты, к которому подозреваемое программное обеспечение может попытаться подключиться, чтобы загрузить неутвержденные данные (для кражи). Если файл сам по себе рассматривается как исполняемый и запускается, то операционная система попытается интерпретировать файл как серию инструкций на своем машинном языке .

Стандарты очень важны для двоичных файлов. Например, двоичный файл, интерпретируемый набором символов ASCII, приведет к отображению текста. Пользовательское приложение может интерпретировать файл по-разному: байт может быть звуком, пикселем или даже целым словом. Сам по себе двоичный код не имеет смысла до тех пор, пока исполняемый алгоритм не определит, что следует делать с каждым битом, байтом, словом или блоком. Таким образом, простое изучение двоичного файла и попытка сопоставить его с известными форматами может привести к неправильному выводу о том, что он на самом деле представляет. Этот факт можно использовать в стеганографии , где алгоритм интерпретирует файл двоичных данных по-разному, чтобы выявить скрытый контент. Без алгоритма невозможно сказать, что скрытый контент существует.

Два файла, которые являются двоично совместимыми, будут иметь одинаковую последовательность нулей и единиц в части данных файла. Однако заголовок файла может быть другим.

Этот термин чаще всего используется для обозначения того, что файлы данных, созданные одним приложением, точно такие же, как файлы данных, созданные другим приложением. Например, некоторые компании-разработчики программного обеспечения производят приложения для Windows и Macintosh, которые являются двоично-совместимыми, что означает, что файл, созданный в среде Windows, взаимозаменяем с файлом, созданным на Macintosh. Это позволяет избежать многих проблем с преобразованием, вызванных импортом и экспортом данных.

Одна из возможных проблем двоичной совместимости между разными компьютерами - это порядковый номер компьютера. Некоторые компьютеры хранят байты в файле в другом порядке. [3]

К проблеме кодировок кириллицы близко примыкает проблема пересылки по почте бинарных файлов, содержащих непечатаемые символы ASCII. По техническим причинам система электронной почты может без искажений передавать только тексты. — т. е. наборы только печатаемых символов ASCII, в которых к тому же достаточно часто встречаются символы новой строки (т. е. строки по длине не превышают некоторой разумной величины). Архивы или исполняемые файлы программ не удовлетворяют ни первому, ни второму из этих условий.

И решается эта проблема сходными методами. Если почтовая программа поддерживает упоминавшийся уже стандарт MIME (Multipurpose Internet Mail Extensions, «Многоцелевое расширение интернетовской почты»), она, скорее всего, воспользуется алгоритмом base64 — одним из тех алгоритмов, которые можно было бы назвать «архиваторами наоборот». И в самом деле, если архиватор преобразует текстовые файлы — так, что они занимают меньше места, — за счет использования непечатаемых символов ASCII, то алгоритмы типа base64, наоборот, «излагают содержа

ние» исходного файла только печатаемыми символами, попутно увеличивая его объем.

Однако поддержка MIME не ограничивается использованием base64. Закодировав подлежащий отправке бинарный файл, почтовая программа должна занести соответствующую информацию в поля заголовка, чтобы программа получателя смогла без труда раскодировать файл и знала, что с ним после этого следует делать. Поле Content Transfer Encoding при этом указывает на метод кодирования (base64), а поле Content Type содержит информацию о типе закодированного файла (а для многих типов — и некоторую служебную информацию, например имя файла). Так, если вы посылаете в письме изображение в формате GIF, в заголовке будет стоять:

Content Type: image/gif; name="logo.jpg"

Content Transfer Encoding: base64

Теперь программа получателя не только сможет рас кодировать пришедший файл, вернув его в исходную бинарную форму, но и будет знать, под каким именем его записать и даже

— какую программу вызвать на обработку этого файла (если у пользователя в настройках операционной системы записано, что файлы формата GIF обрабатываются, к примеру, программой Photoshop).

Разобранный выше пример предполагает, что в теле письма не содержится ничего, кроме столбца букв и цифр, представ ляющего собой закодированный по base64 бинарный файл. Но что делать, если вы хотите сопроводить посылаемый файл собственноручной припиской? На этот случай MIME предусматривает возможность создания «составных» писем из нескольких частей. При этом в заголовке письма стоит следующее:

Content Type: multipart/mixed; boundary= 4Е611А4Е6А69"

чти в переводе на русский язык означает: письмо состоит из нескольких частей разных типов, причем границы («boundary») между частями помечены строками символов "———— 4Е611А4Е6А69". Вот как будет выглядеть тело такого письма:

This is a multi part message in MIME format.

Content Type: text/plain; charset=koi8 r

Content Transfer Encoding: 8bit

Привет! Вот тебе обещанный логотип.

Content Type: image/gif; name^'logo.jpg" Content Transfer Encoding: base64 Content Disposition: inline; filename^'logo.jpg"

R01GODdhxgHtAfcAAP////z19vr6/Pr6+/nr7Pbg4/'X2+PTW2vHx9fHM OfOx907Cx+2t8ezs 8eu4vuittefo7ufo7eWj q+OZoulj 6uGTneCPmd3f593f5t2FkNp6htna49j a49dwfdTW4NRm dNPV39Jca8/R3M9SYcxHWMrN2crM2crM2Mk9T8YzRcXI1sXI1cXH lcMpPMHDOsEfM8DDOsDD

Первая фраза, «This is a multi part message. », вставляется' почтовой программой отправителя на тот случай, если программа получателя не будет знакома с MIME и покажет своему пользователю текст письма «как есть» — т. е. ровно в том же виде, что и на этой странице книги. Если же программа чтения почты поддерживает MIME, она проигнорирует все вплоть до первого вхождения строки разделителя.

Сразу после разделителя, открывающего очередную часть, располагаются «локальные» MIME заголовки, указывающие на тип каждой части письма. Согласно этим сведениям, первая часть письма в нашем примере содержит русский текст в кодировке КОИ8, а вторая — изображение.в формате GIF из файла logo.jpg. То же самое письмо в окне почтовой программы, поддерживающей MIME и умеющей к тому же выводить на экран изображения из GIF файлов, показано на рис. 30.

До того как стандарт MIME получил широкое распространение, вместо base64 употреблялся другой похожий алгоритм, называе мый uuencode/uudecode. Достоинство uuencode — то, что этот метод приводит к менее значительному увеличению размера кодируемого файла, чем base64, а главный недостаток — то, что он не включен в стандарт MIME и потому не может работать пол ностью автоматически. Если закодировать по uuencode и вставить в письмо бинарный файл некоторые почтовые программы могут почти автоматически, то, чтобы извлечь его оттуда, вам придется как минимум показать программе место, откуда начинать раскодировать (а поскольку большие бинарные файлы при кодировке часто разбиваются на части, то вам придется еще потрудиться, собирая эти части воедино). Вот как выглядит начало бинарного файла, закодированного по алгоритму uuencode:

begin 644 BOOK.ARJ

M<0'M' • '@ZBO' '@4'•'•' ' C1'4,>2E$" ,R\' ' ••<WIO]' "»• • " . 2U65»' '5 MX VES»' •

•'BtWB^ Qa+OJZSSZF^RO.YROZ'^UZISD'^PXCS'IOA M<V= )'NPW=9%Q.8@?2=(F

M__ZJN6V.X1R$> 1 (A"_«[W:UMIN[W</__3SZ;N:JN:B R>FNF:J?HGTOQ34F

Методом uuencode следует пользоваться, когда вы подо зреваете, что почтовая программа получателя не поддерживает MIME. К сожалению, этот метод нельзя рекомендовать на все случаи жизни, так как многие программы с поддержкой MIME, наоборот, не имеют никакого представления об uuencode. (Если вы пользуетесь такой программой, существуют отдельные ути литы для шифровки/расшифровки файлов по uuencode.) А лучше всего в любом случае, прежде чем посылать кому то бинарный файл, выяснить, с каким алгоритмом шифрования может работать почтовая программа вашего адресата.

Размер закодированного файла больше размера исходного примерно на 30% в случае uuencode и 40% в случае base64. Поэтому, когда вы посылаете хоть сколько нибудь сжимаемые бинарные файлы (например, ехе программы), желательно перед обработкой кодировщиком их заархивировать, чтобы уменьшить размер письма. Более того, даже для посылки обычного текста большого объема имеет смысл файл с этим текстом заархивировать, а затем закодировать — размер письма будет меньше, чем объем исходного текста. (Конечно, вы должны быть уверены, что получатель письма сможет произвести обратные действия — декодирование и разархивирование.)

Uudecode для бедных

Отдельные утилиты и целые почтовые программы, поддерживающие как uuencode/uudecode, так и base64, совсем несложно

Метод хорош тем, что работает с коробки. Надо только написать свою функцию отправки файла (немного измененный пример из официальной документации):


Таким способом можно отправлять даже большие файлы, так как PHP будет читать файл и сразу отдавать его пользователю по частям. В документации четко сказано, что readfile() не должен создавать проблемы с памятью.

  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Файл читается в внутренний буфер функции readfile(), размер которого составляет 8кБ (спасибо 2fast4rabbit)

2. Читаем и отправляем файл вручную

Метод использует тот же Drupal при отправке файлов из приватной файловой системы (файлы недоступны напрямую по ссылкам):

  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Позволяет сэкономить память сервера

3. Используем модуль веб сервера

3a. Apache

Модуль XSendFile позволяет с помощью специального заголовка передать отправку файла самому Apache. Существуют версии по Unix и Windows, под версии 2.0.*, 2.2.* и 2.4.*

В настройках хоста нужно включить перехват заголовка с помощью директивы:

Также можно указать белый список директорий, файлы в которых могут быть обработаны. Важно: если у Вас сервер на базе Windows путь должен включать букву диска в верхнем регистре.

Пример отправки файла:

3b. Nginx

Nginx умеет отправлять файлы из коробки через специальный заголовок.

Для корректной работы нужно запретить доступ к папку напрямую через конфигурационный файл:

Пример отправки файла (файл должен находиться в директории /some/path/protected):

  • Скрипт завершается сразу после выполнения всех инструкций
  • Физически файл отправляется модулем самого веб сервера, а не PHP
  • Минимальное потребление памяти и ресурсов сервера
  • Максимальное быстродействие

Update: Хабраюзер ilyaplot дает дельный совет, что лучше слать не application/octet-stream , а реальный mime type файла. Например, это позволит браузеру подставить нужные программы в диалог сохранение файла.

Т екстовые файлы хранят данные в виде текста (sic!). Это значит, что если, например, мы записываем целое число 12345678 в файл, то записывается 8 символов, а это 8 байт данных, несмотря на то, что число помещается в целый тип. Кроме того, вывод и ввод данных является форматированным, то есть каждый раз, когда мы считываем число из файла или записываем в файл происходит трансформация числа в строку или обратно. Это затратные операции, которых можно избежать.

Текстовые файлы позволяют хранить информацию в виде, понятном для человека. Можно, однако, хранить данные непосредственно в бинарном виде. Для этих целей используются бинарные файлы.

Выполните программу и посмотрите содержимое файла output.bin. Число, которое ввёл пользователь записывается в файл непосредственно в бинарном виде. Можете открыть файл в любом редакторе, поддерживающем представление в шестнадцатеричном виде (Total Commander, Far) и убедиться в этом.

Запись в файл осуществляется с помощью функции

Функция возвращает число удачно записанных элементов. В качестве аргументов принимает указатель на массив, размер одного элемента, число элементов и указатель на файловый поток. Вместо массив, конечно, может быть передан любой объект.

Запись в бинарный файл объекта похожа на его отображение: берутся данные из оперативной памяти и пишутся как есть. Для считывания используется функция fread

Функция возвращает число удачно прочитанных элементов, которые помещаются по адресу ptr. Всего считывается count элементов по size байт. Давайте теперь считаем наше число обратно в переменную.

fseek

Одной из важных функций для работы с бинарными файлами является функция fseek

Эта функция устанавливает указатель позиции, ассоциированный с потоком, на новое положение. Индикатор позиции указывает, на каком месте в файле мы остановились. Когда мы открываем файл, позиция равна 0. Каждый раз, записывая байт данных, указатель позиции сдвигается на единицу вперёд.
fseek принимает в качестве аргументов указатель на поток и сдвиг в offset байт относительно origin. origin может принимать три значения

  • SEEK_SET - начало файла
  • SEEK_CUR - текущее положение файла
  • SEEK_END - конец файла. К сожалению, стандартом не определено, что такое конец файла, поэтому полагаться на эту функцию нельзя.

В случае удачной работы функция возвращает 0.

Дополним наш старый пример: запишем число, затем сдвинемся указатель на начало файла и прочитаем его.

Вместо этого можно также использовать функцию rewind, которая перемещает индикатор позиции в начало.

В си определён специальный тип fpos_t, который используется для хранения позиции индикатора позиции в файле.
Функция

используется для того, чтобы назначить переменной pos текущее положение. Функция

используется для перевода указателя в позицию, которая хранится в переменной pos. Обе функции в случае удачного завершения возвращают ноль.

возвращает текущее положение индикатора относительно начала файла. Для бинарных файлов - это число байт, для текстовых не определено (если текстовый файл состоит из однобайтовых символов, то также число байт).

Рассмотрим пример: пользователь вводит числа. Первые 4 байта файла: целое, которое обозначает, сколько чисел было введено. После того, как пользователь прекращает вводить числа, мы перемещаемся в начало файла и записываем туда число введённых элементов.

Вторая программа сначала считывает количество записанных чисел, а потом считывает и выводит числа по порядку.

Примеры

1. Имеется бинарный файл размером 10*sizeof(int) байт. Пользователь вводит номер ячейки, после чего в неё записывает число. После каждой операции выводятся все числа. Сначала пытаемся открыть файл в режиме чтения и записи. Если это не удаётся, то пробуем создать файл, если удаётся создать файл, то повторяем попытку открыть файл для чтения и записи.

2. Пишем слова в бинарный файл. Формат такой - сначало число букв, потом само слово без нулевого символа. Ели длина слова равна нулю, то больше слов нет. Сначала запрашиваем слова у пользователя, потом считываем обратно.

3. Задача - считать данные из текстового файла и записать их в бинарный. Для решения зачи создадим функцию обёртку. Она будет принимать имя файла, режим доступа, функцию, которую необходимо выполнить, если файл был удачно открыт и аргументы этой функции. Так как аргументов может быть много и они могут быть разного типа, то их можно передавать в качестве указателя на структуру. После выполнения функции файл закрывается. Таким образом, нет необходимости думать об освобождении ресурсов.

4. Функция saveInt32Array позволяет сохранить массив типа int32_t в файл. Обратная ей loadInt32Array считывает массив обратно. Функция loadInt32Array сначала инициализирует переданный ей массив, поэтому мы должны передавать указатель на указатель; кроме того, она записывает считанный размер массива в переданный параметр size, из-за чего он передаётся как указатель.

5. Создание таблицы поиска. Для ускорения работы программы вместо вычисления функции можно произвести сначала вычисление значений функции на интервале с определённой точностью, после чего брать значения уже из таблицы. Программа сначала производит табулирование функции с заданными параметрами и сохраняет его в файл, затем подгружает предвычисленный массив, который уже используется для определения значений. В этой программе все функции возвращают переменную типа Result, которая хранит номер ошибки. Если функция отработала без проблем, то она возвращает Ok (0).

6. У нас имеются две структуры. Первая PersonKey хранит логин, пароль, id пользователя и поле offset. Вторая структура PersonInfo хранит имя и фамилию пользователя и его возраст. Первые структуры записываются в бинарный файл keys.bin, вторые структуры в бинарный файл values.bin. Поле offset определяет положение соответствующей информации о пользователе во втором файле. Таким образом, получив PersonKey из первого файла, по полю offset можно извлечь из второго файла связанную с данным ключом информацию.

Зачем так делать? Это выгодно в том случае, если структура PersonInfo имеет большой размер. Извлекать массив маленьких структур из файла не накладно, а когда нам понадобится большая структура, её можно извлечь по уже известному адресу в файле.

email

Всё ещё не понятно? – пиши вопросы на ящик

Читайте также: