Как сделать загрузчик файлов

Обновлено: 07.07.2024

Всем привет. Я хочу рассказать о создании загрузчика изображений для своего первого web-проекта. Я постараюсь объяснить, какие решения я видел, и какие подводные камни встретились на моем пути. Ну и, собственно, как эти камни можно обойти. Надеюсь, мой опыт кому-нибудь поможет.

Для начала опишу основную задачу: необходимо создать загрузчик изображений(bmp, png, jpg), с последующим их сохранением на сервере, а также с созданием копий изображений различного размера. Также желательно обеспечить соответствие дизайна загрузчика стилю сайта, и удобный интерфейс пользователя. И самое главное – загрузчик должен максимально поддерживаться браузерами.

Решение первое. HTML4

Конечно же, это самое простое и очевидное. Создать форму, засунуть туда input-file, и обработать на сервере php-скриптом:


Теперь необходимо создать копии меньшего разрешения. Тут можно воспользоваться различными библиотеками обработки изображений. Например, Imagick. Именно так я вначале и сделал. На локальном хосте все работало замечательно. Потом я выбрал недорогой хостинг, поместил туда проект. Начал тестировать. И вот тут вышел главный облом. Для изображений с хорошим разрешением (2500х1900) не создавались маленькие копии. Многие, наверное, догадались почему. Покопавшись в логах, а также приложив умственные усилия, до меня дошло. Когда начинаешь обрабатывать изображения, и работать со всей матрицей, требуется немало оперативной памяти. И мой достаточно скромный тариф на хостинге предоставлял её не очень-то много.

И вот это уже была проблема. Можно, конечно, взять тариф получше. Но кардинально это ситуацию не изменит. При дополнительной нагрузке произойдет то же самое. Подход неверен по сути. Производить манипуляции с изображением надо не на сервере, а на клиенте. И кроссбраузерный html+javascript тут не подходил.

Решение второе. Flash

  • асинхронная загрузка
  • возможность пакетной загрузки
  • возможность выводить превью изображений
  • варианты дизайна не ограничены


Метод browse вызывает диалог загрузки файлов. Тут есть одна тонкость: метод выполнится только в том случае, если код вызывается в слушателе события EVENT.CLICK какого-нибудь элемента.

Также стоит остановиться на описании класса FileReference. Он нужен для загрузки локального изображения и передачи его на сервер. Метод load нужен для загрузки, upload – для передачи на сервер. Здесь есть ещё одна тонкость: при загрузке на сервер с помощью FileReference куки передаются только из IE(спасибо за информацию Demetros). Поэтому, если вы хотите, например, работать в рамках одной сессии, то придется достать куки из браузера с помощью вызова функции javascript. Лучше это делать из самой флешки. Для этого подойдет ExternalInterface. Далее записываем нужные нам куки в URLVariables.

Вопрос создания уменьшенных копий я не буду рассматривать, есть много библиотек, способных это сделать. Однако для отправки на сервер эти данные должны быть представлены в виде ByteArray.
Теперь рассмотрим, как нам организовать отправку этих данных на сервер. С помощью обычной переменной URLVariables с последущем добавлением в URLRequest это сделать не получится. Поэтому придется формировать шапку запроса самим. URLRequest позволяет это сделать. В итоге создаем класс, который занимается отправкой данных на сервер:


Вот такое решение. При желании можно выводить превью картинок сразу же, или передавать в javascript в виде base64. Ну это уже кому как нравится.

Решение третье. HTML5

Сразу скажу, что с помощью html5 я загрузчик не реализовывал, однако для относительной полноты картины (java-апплеты я брать не стал) об этом решении стоит упомянуть. Скорее всего, в будущем это станет наилучшим способом решения этой задачи. Однако пока ещё в ходу старые браузеры, да и в новых File API ещё не до конца проработан. Также стоит упомянуть про неизменяемый input-file. В современных браузерах можно вызвать программно метод click, а сам input скрыть.

Такое решение работает почти во всех современных браузерах. Кроме одного. Угадайте какого…
Не угадали, Opera. В версиях до 11.52 включительно так сделать нельзя. Поэтому наложение грима на input-file до сих пор остается проблемой.

Все течет, все меняется, но только input[type=file] как портил нервы всем начинающим веб-разработчикам, так и продолжает это делать до сих пор. Вспомните себя N лет назад, когда вы только начинали постигать азы создания веб-сайтов. Молодой и неопытный, вы искренне удивлялись, когда кнопка выбора файла напрочь отказывалась менять цвет своего фона на ваш любимый персиковый. Именно в тот момент вы впервые столкнулись с этим несокрушимым айсбергом под названием «Загрузка файлов», который и по сей день продолжает «топить» начинающих веб-разработчиков.

На примере создания поля для загрузки файлов я покажу вам, как правильно прятать input[type=file] , настраивать фокус на объекте, у которого фокуса быть не может, обрабатывать события Drag-and-Drop и отправлять файлы через AJAX. А также я познакомлю вас с парой браузерных багов и путями их обхода. Статья написана для новичков, но в некоторых моментах может быть полезна и занимательна даже для матерых разработчиков.

Разметка и первичные стили

Начнем с HTML-разметки:


Пожалуй, главным элементом, на который стоит обратить внимание, является


Спецификация HTML не позволяет нам накладывать визуальные свойства непосредственно на input[type=file] , но мы имеем тэг label , нажатие на который вызывает клик по элементу формы, к которому он привязан. К нашей радости, данный тэг никаких ограничений в стилизации не имеет: мы можем делать с ним все, что захотим.

Вырисовывается план действий: стилизуем метку как нам угодно, а сам input[type=file] прячем с глаз долой. Для начала настроим общие стили страницы:


Теперь стилизуем нашу метку:



То, к чему мы стремимся ( input[type=file] убран из разметки):

Безусловно, можно было отцентровать метку, добавить фон и границу, получив полноценную кнопку, но наш приоритет — Drag-and-Drop.

Прячем input

Теперь нам нужно спрятать input[type=file] . Первое, что бросается в голову — свойства display: none и visibility: hidden . Но тут не все так просто. На некоторых старых браузерах клик по метке перестанет производить какой-либо эффект. Но это не все. Как известно, невидимые элементы не могут получать фокус, а кто бы что ни говорил, фокус важен, так как для некоторых людей это единственная возможность взаимодействия с сайтом. Так что этот способ нас не устраивает. Пойдем обходным путем:


Абсолютно спозиционируем наш input[type=file] относительно его родительского блока, уменьшим до 0.1px , сделаем прозрачным и установим его z-index меньше, чем у родителя, чтоб, так сказать, наверняка.

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

Настраиваем фокус

Так как наш input[type=file] физически присутствует на страницу, он имеет возможность получать фокус. То есть, если мы будем нажимать на странице клавишу Tab , то в какой-то момент фокус перейдет на input[type=file] . Но проблема в том, что мы этого не увидим: выделяться будет поле, которое мы скрыли. Да, если в этот момент мы нажмем Enter , то диалоговое окно откроется и все будет работать как надо, вот только как мы поймем, что нажимать уже пора?

Наша задача — определенным образом выделить метку в момент, когда фокус расположен на поле загрузки файлов. Но как нам это сделать, если метка получать фокус не может? Знатоки CSS3 сразу же подумают о псевдоклассе :focus , который определяет стили для элементов в фокусе, и селекторах + или

, которые выбирают правых соседей: элементы, расположенные на том же уровне вложенности, идущие после выбранного элемента. Если учесть, что в нашей разметке input[type=file] расположен прямо перед тэгом label , имеет место быть следующая запись:


​Но опять же, не все так просто. Для начала давайте обсудим, каким образом нам следует выделить метку. Как известно, все современные и не очень браузеры имеют уникальные свойства по умолчанию для элементов в фокусе. В основном, это свойство outline , которое создает вокруг элемента обводку, отличающуюся от border тем, что не изменяет размер элемента и может быть отодвинута от него. Как правило, люди пользуются только одним браузером, поэтому привыкают именно к его стандартам. Чтобы людям было проще ориентироваться на нашем сайте, мы должны постараться настроить фокус так, чтобы он выглядел максимально естественно для большинства популярных современных браузеров. В теории, с помощью JavaScript можно получить информацию о том, через какой браузер пользователь открыл сайт, и в соответствии с этим настроить стили, но в рамках статьи, предназначенной в первую очередь для новичков, эта тема слишком сложна и громоздка. Постараемся обойтись малой кровью.

В браузерах, основанных на движке WebKet (Google Chrome, Operа, Safari), свойство по умолчанию для элементов в фокусе имеет вид:


Здесь -webkit-focus-ring-color — специфичный только для данного движка цвет фокусной обводки. То есть, эта строчка будет работать исключительно в WebKit-браузерах, а это именно то, что нам нужно. Укажем данное свойство для нашей метки:


Открываем Google Chrome или Opera, смотрим. Все работает как надо:

Посмотрим, как обстоят дела с фокусом в Mozilla Firefox и Microsoft Edge. Для этих браузеров свойство по умолчанию имеет вид:

К сожалению, префикс -moz- со свойством outline работать не будет. Поэтому нам придется выбирать, какое из этих двух свойств мы выберем. Так как количество пользователей Firefox значительно выше, рациональнее отдать предпочтение именно этому браузеру. Это не значит, что мы лишим пользователей Edge и других браузеров возможности видеть, где сейчас фокус, просто он у них будет выглядеть «неродным». Что ж, приходится идти на жертвы.

Добавляем стиль из Mozilla Firefox перед стилем для WebKit: сначала все браузеры применят первое свойство, а затем те, которые могут (Google Chrome, Opera, Safari и др.), применят второе.


И вот тут начинается странное: в Edge все работает нормально, а вот Firefox по каким-то неведомым причинам отказывается применять свойства к метке при фокусе на input[type=file] . Причем само событие focus случается — проверил через JavaScript. Более того, если принудительно установить фокус на поле выбора файла через инструменты разработчика, то свойство применится и наша обводка появится! Видимо, это баг самого браузера, но если у кого-то есть идеи, почему такое происходит — пишите в комментариях.

Ну ничего, нормальные герои всегда идут в обход. Как я сказал ранее, событие focus случается, а значит, регулировать свойства мы можем прямиком из JavaScript. Но для этого нам придется поменять логику нашего селектора:


Опишем класс .focus для нашей метки и будем добавлять его каждый раз, когда input[type=file] получает фокус и убирать, когда теряет.


Теперь все работает как надо. Поздравляю, с фокусом мы разобрались.

Drag-and-Drop

Работа с Drag-and-Drop осуществляется путем отслеживания специальных браузерных событий: drag, dragstart, dragend, dragover, dragenter, dragleave, drop . Подробное описание каждого из них вы с легкостью сможете найти в интернете. Мы будем отслеживать только некоторые из них.

Для начала определим Drag-and-Drop-элемент:

Затем опишем в CSS специальный класс, который будем присваивать dropZone , когда курсор, тянущий файл, будет прямо над ним. Это нужно, чтобы визуально проинформировать пользователя о том, что файл уже можно отпустить.


Теперь перейдем в JS-файл. Для начала, нам необходимо отменить все действия по умолчанию на события Drag-and-Drop. Например, одно из таких событий — открытие кинутого файла браузером. Нам это совершенно не нужно, поэтому пропишем следующие строчки:


В jQuery вызов оператора return false эквивалентен вызову сразу двух функций: e.preventDefault() и e.stopPropagation() .

Начнем описывать свой собственный обработчик событий. Поступим так же, как делали с фокусом, но на этот раз будем отслеживать события dragenter и dragover для добавления класса и событие dragleave для его удаления:

А происходит это мерцание из-за того, что при наведении курсора на дочерний элемент dropZone , будь то картинка или div с полем выбора файлов и меткой, по какой то причине срабатывает событие dragleave . Нам очевидно, что поле мы не покидаем, а вот браузерам, почему-то, нет, и из-за этого они без зазрения совести убирают класс .focus у dropZone .

И вновь нам придется как-то выкручиваться. Если браузер сам не понимает, что поле мы не покидаем, придется ему помочь. А делать мы это будем через дополнительные условия: вычислим координаты мыши относительно dropZone , а затем проверим, вышел ли курсор за пределы блока. Если вышел, значит убираем стиль:



И все, проблема решена! Вот так выглядит наше поле с файлом внутри:

Переходим к обработке самого события drop . Но для начала вспомним, что, помимо Drag-and-Drop, у нас есть input[type=file] , и каждый из этих способов независим по своей сути, но должен выполнять одинаковые действия: загружать файлы. Поэтому я предлагаю создать отдельную универсальную для обоих методов функцию, в которую мы будем передавать файлы, а она уже будет решать, что с ними сделать. Назовем ее sendFiles() , но опишем чуть позже. Для начала обработаем событие drop :


Сначала уберем класс .dragover у dropZone . Затем получим массив, содержащий файлы. Если вы используете jQuery, то путь будет e.originalEvent.dataTransfer.files , если пишите на чистом JS, то e.dataTransfer.files . Ну а затем передаем массив в нашу пока еще нереализованную функцию.

Теперь проработаем способ загрузки через input[type=file] :


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

Отправка файлов через AJAX

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


В переменную maxFileSize занесем максимальный размер файла, который будем отправлять на сервер. Функцией FormData() мы создадим новый объект класса FormData , позволяющий формировать наборы пар ключ-значение. Такой объект можно легко отправлять через AJAX. Далее используем jQuery конструкцию .each для массива files , которая применит заданную нами функцию для каждого его элемента. В качестве аргументов в функцию будут передаваться порядковый номер элемента и сам элемент, которые мы будем обрабатывать как index и file соответственно. В самой функции мы проверим файл на соответствие нашим критериям: размер меньше пяти мегабайт, а тип — PNG или JPEG. Если файл проходит проверку, то добавляем его в наш объект FormData путем вызова функции append() . Ключом послужит строка 'photos[]' , квадратные скобки на конце которой обозначат, что это массив, в котором может быть несколько объектов. Самим объектом будет file .

Теперь все готово для отправки файлов через AJAX. Добавим в нашу функцию следующие строчки:

Поздравляю, теперь вы умеете создавать свое собственное поле загрузки файлов! Конечно же, я не позиционирую свой способ как единственно верный и правильный. Своей задачей я ставил показать общий ход решения данной задачи, подходящий в первую очередь для новичков. Если вы считаете, что где-то что-то можно было сделать лучше — пишите в комментариях, обсудим!

Это статья была написана для людей, которым всегда интересно знать как работают разные вещи. Для тех разработчиков которые обычно пишут свои программы на высоком уровне, C, C++ или Java — не важно, но при этом столкнулись с необходимостью сделать что-то на низком уровне. Мы будем рассматривать низкоуровневое программирование на примере работы bootloader-а.

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

Что такое Boot Loader

Boot loader — это программа, которая записана на первом секторе жесткого диска. BIOS автоматически считывает всё содержимое первого сектора в память, сразу после включения питания. Первый сектор также называется главной загрузочной записью. На самом деле, это не является обязательным для первого сектора жесткого диска для загрузки чего либо. Это название было исторически сложившиеся, так как разработчики использовали такой механизм для загрузки операционной системы.

Будьте готовы погружаться глубже

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

И так, какой язык Вы должны знать, чтобы написать Boot Loader

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

В этой статье в основном будет использоваться язык C++. Но если вы знаете C, то вам будет легко узнать необходимые C++ элементы. В общем, даже знание языка C будет достаточно, но тогда вам придется изменять исходный код примеров.

И так, для разработки простого загрузчика вы должны знать, C или C++, а также было бы не плохо если вы знаете немного Ассемблера.

Какой компилятор вам нужен

Чтобы использовать технологию смешанного кода, нужно по крайней мере два компилятора: для ассемблера и для C/C++, а также компоновщик который объединит объектные файлы(.obj) в один исполняемый файл.

Теперь, давайте поговорим о некоторых особых моментов. Есть два режима функционирования процессора: реальный и защищенный режим. Реальный режим является 16-битным и имеет некоторые ограничения. Защищенный режим является 32-битным и полностью используется операционной системой. Когда компьютер только начинает работу, процессор работает в 16-битном режиме. Таким образом, чтобы написать программу и получить исполняемый файл, вам понадобится компилятор и компоновщик для ассемблера для 16-битного режима. Для C/C++ вам потребуется только компилятор, который умеет создавать объектные файлы для 16-битного режима.

Современные компиляторы сделаны для 32-разрядных приложений, поэтому мы не сможем их использовать.

Я пробовал несколько бесплатных и коммерческих компиляторов для 16-битного режима и выбрал продукт от Microsoft. Компилятор вместе с компоновщиком для ассемблера, C и C++ включены в Microsoft Visual Studio 1.52, его можно скадать с официального сайта компании. Некоторые подробности о компиляторов которые нам нужны приведены ниже.

ML 6,15 — компилятор ассемблера от Microsoft для 16-битного режима.
LINK 5,16 — компоновщик, который умеет создавать COM-файлы для 16-битного режима.
CL — С, С++ компилятор для 16-битного режима.

Вы также можете использовать несколько альтернативных вариантов.

DMC — бесплатный компилятор для компиляции ассемблера, C, C++ для 16 и 32-битном режиме Digital Mars.
LINK — бесплатный компоновщик для компилятора DMC.

Есть также некоторые продукты от Borland.

BCC 3,5 — С, С++ компилятор, который умеет создавать файлы для 16-битного режима.
TASM — компилятор асемблера для 16-битного режима.
TLINK — компоновщик, который может создавать файлы COM для 16-битного режима.

Все примеры кода в этой статьи, были разработаны с инструментами от Microsoft.

Как система загружается

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


После того, как управление было передано по адресу 0000:7C00, Master Boot Record (MBR) начинает свою работу и запускает загрузку операционной системы.

Давайте перейдем к кодированию

В следующих разделах мы будем непосредственно заняты низкоуровневым программированием — мы будем писать наш собственный загрузчик.

Архитектура программы
  1. Правильная загрузка в память по адресу 0000:7 C00.
  2. Вызов BootMain функции, которую мы написали в языке высокого уровня.
  3. Вывести на дисплей фразу — ”Hello, world…", from low-level.


Первый объект это StartPoint, который написан исключительно в ассемблере, поскольку в языках высокого уровня нет необходимых нам инструкции. Это говорит компилятору, какой тип памяти должен использоваться, и адрес команды в RAM, которая должна выполняться после его чтения. Он также исправляет регистры процессора и передает управление функции BootMain, которая написано на языке высокого уровня.

Следующий объект- BootMain — является аналогом main, что, в свою очередь является основной функцией в которой сконцентрированы все функции программы.

Среда разработки

Здесь я использую стандартные среды разработки Microsoft Visual Studio 2005 или 2008. Вы можете использовать любые другие инструменты, но я уверен, что эти два, с некоторыми настройками, компилируют и работают легко и удобно.

Сначала мы должны создать проект Makefile Project, где будет выполнена основная работа.


File->New\Project->Общие\Makefile Project

BIOS прерывания и очистка экрана

BIOS предлагает ряд прерываний для работы с железом, таким как видеокарта, клавиатура, системный диск. Каждое прерывание имеет следующую структуру:


Где «number_of_interrupt» является числом прерывания.

Каждое прерывание имеет некоторое количество параметров, которые должны быть установлены до его вызова. Регистр процессора — ah, всегда несет ответственность за количество функций для текущего прерывания, и другие регистры обычно используются для других параметров текущей операции. Давайте посмотрим, как работа прерывания номер 10h выполняется на ассемблере. Мы будем использовать 00-функцию, она меняет видео режим и очищает экран:

Мы будем рассматривать только те прерывания и функции, которые будут использоваться в нашем приложении. Нам понадобится:

«Смешанный код»

Компилятор C++ поддерживает встроенный Ассемблер, то есть при написании кода на языке высокого уровня вы можете также использовать язык низкого уровня. Инструкции ассемблера, которые используются на высоком уровне, также называют asm вставками. Они состоят из ключевого слова "__asm" и блока ассемблерных инструкций:


Чтобы продемонстрировать пример смешанного кода мы будем использовать ранее упомянутый код на ассемблере, который выполняет очистку экрана и объединим его с кодом написанный на C++.

CString реализация

CString класс предназначен для работы со строками. Он включает в себя метод Strlen(), который получает в качестве параметра указатель на строку и возвращает количество символов в этой строке.

  1. TextOut() — выводит строку на экране.
  2. ShowCursor() — управляет курсором представления на экране: показать, скрыть.
  3. ClearScreen() — изменяет видео режим и таким образом очищает экран.
CDisplay — реализация
Types.h — реализация

Types.h является заголовочным файлом, который включает определения типов данных и макросов.

BootMain.cpp — реализация

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

StartPoint.asm — реализация

Давайте соберем все

Создание COM файла

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

Поместите компиляторы и компоновщик в каталог проекта. В том же каталоге, мы создаем командный файл и заполняем в соответствии с примером (можно использовать любой каталог вместо VC152, главное чтобы компиляторы и компоновщик находились в нем).:

Ассамблирование — автоматизация

В качестве заключительного этапа в этом разделе мы опишем как превратить Microsoft Visual Studio 2005, 2008, в среду разработки с поддержкой любого компилятора. Для этого нужно перейти в свойствах проекта: Project->Properties->Configuration Properties\General->Configuration Type.

Вкладка Configuration Properties включает в себя три пункта: General, Debugging и NMake. Выберите NMake и укажите путь к «build.bat» в Build Command Line и Rebuild Command Lin.

Если все сделано правильно, то вы можете скомпилировать нажав клавиши F7 или Ctrl + F7. При этом вся сопутствующие информация будет отображаться в окне вывода. Основным преимуществом здесь является не только автоматизация сборки, но и мониторинг ошибок в коде если они будут.

Тестирование и демонстрация

Этот раздел расскажет, как увидеть сделанный загрузчик в действии, как выполнить тестирование и отладку.

Как проверить загрузчик

Вы можете проверить загрузчик на реальном оборудовании или с использованием разработанных для этих целей виртуальных машинам — VMware. Тестирование на реальном оборудовании дает вам больше уверенности, что он работает также как и на виртуальной машине. Конечно, мы можем сказать, что VmWare отличный способ для тестирования и отладки. Мы рассмотрим оба метода.

Прежде всего, нужен инструмент, чтобы записать наш загрузчик на виртуальный или физический диск. Насколько я знаю, есть несколько бесплатных и коммерческих консолей и GUI приложений. Я использовал Disk Explorer для NTFS 3.66 (версия для FAT, называется Disk Explorer для FAT) для работы в ОС Windows и Norton Disk Editor 2002 для работы в MS-DOS.

Я опишу только Disk Explorer для NTFS 3,66 потому что это самый простой способ и подходит для наших целей больше всего.

Тестирование с помощью виртуальной машины VmWare
Создание виртуальной машины

Нам понадобится VmWare версия программы 5.0, 6.0 или выше. Чтобы проверить загрузчик мы создадим новую виртуальную машину с минимальным размером диска, например, 1 Gb. Отформатируйте его в файловую систему NTFS. Теперь нам нужно отобразить отформатированный жесткий диск на VmWare в качестве виртуального диска. Для этого выберите:

File->Map or Disconnect Virtual Disks.

После этого появится окно. Там вы должны нажать кнопку «Map». В следующем появившемся окне вы должны указать путь к диску. Теперь Вы также можете выбрать букву диска.

Не забудьте снять флажок «Open file in read-only mode (recommended)». После того как выполнили все выше описанные индикации диск должен быть доступен в режиме только для чтения чтобы избежать повреждения данных.

После этого мы можем работать с диском виртуальной машины, как с обычными логическим диском в ОС Windows. Теперь мы должны использовать Disk Explorer для NTFS 3,66 чтобы записать загрузочную запись с позиции 0.

Работа с Disk Explorer для NTFS

После запуска программы мы идем в наш диск (File-> Drive). В появившемся окне идем в раздел логические диски и выбираем наш созданный диск(в моем случае это Z).

Теперь мы выбираем меню пункт View как Hex команды. В это появившемся окне мы можем видеть информацию диска в 16-разрядном представлении, разделенная на сектора. Сейчас у нас только 0-ли, так как диск пуст, пока что.

Сейчас мы должны записать наш загрузчик в первый сектор. Мы устанавливаем маркер в положение 00, как это показано на предыдущей картинке. Чтобы скопировать загрузчик мы используем пункт меню Edit->Paste from file command. В открывшемся окне укажите путь к файлу и кликните Open. После этого содержимое первого сектора должен измениться и выглядеть, как это показано на картинке — если вы, конечно, ничего не меняли в коде.

Вы также должны записать подпись 55AAh по позиции 1FE от начала сектора. Если вы не сделаете это, BIOS проверит последние два байта, и не найдя указанную подписи, будет считать что этот сектор не является загрузочным и не загрузит его в память.

Для переключения в режим редактирования нажмите клавишу F2 и напишите необходимые номера — 55AAh подписи. Чтобы выйти из режима редактирования нажмите ESC.

Теперь нам нужно подтвердить записанные данные.

Чтобы применить записанное мы идем в Tools-> Options, теперь мы идем в пункт Mode и выбираем метод записывания — Virtual Write и нажмите кнопку Write.

Большую часть рутинных действий закончили, наконец, и теперь вы можете видеть, что мы разработали с самого начала этой статьи. Давайте вернемся к VwWare чтобы отключить виртуальный диск (File->Map or Disconnect Virtual Disks … and click Disconnect).

Давайте запустим виртуальную машину. Мы видим теперь, как из глубины царства машинных кодов появляются знакомые строки — «Hello World… », from low-level. ".

Тестирование на реальном оборудовании

Тестирование на реальном оборудовании почти такая же, как и на виртуальной машине, за исключением того, что если что-то не работает, вам потребуется намного больше времени, чтобы восстановить ее, чем создать новую виртуальную машину. Чтобы проверить загрузчик не имея возможность потерять данные (все может случиться), я предлагаю использовать флэш-накопитель, но сначала вы должны перезагрузить компьютер, зайдите в BIOS и убедитесь, что он поддерживает загрузку с флэш-накопителя. Если он поддерживает его, то все в порядке. Если нет, то вы должны ограничить тестированием на виртуальной тестовой машине.

Процесс написание загрузчика на флэш-диск в Disk Explorer для NTFS 3,66 такой же как и для виртуальной машины. Вы просто должны выбрать сам жесткий диск вместо своего логического раздела.

Заключение

В этой статье мы рассмотрели, что такое загрузчик, как работает BIOS, и как компоненты системы взаимодействуют при загрузке системы. Практическая часть дала нам понимание о том, как можно разработать свой собственный, простой загрузчик. Мы продемонстрировали технологию смешанного кода и процесс автоматизации сборки с использованием Microsoft Visual Studio 2005, 2008.

Конечно, это лишь малая часть по сравнению с огромной темой низкоуровневого программирования, но если вам было интересна это статья — то это круто.


Известный факт, что поле для загрузки файлов трудно стилизовать так, как хочется разработчику. Многие просто скрывают его и добавляют кнопку, которая открывает диалог выбора файлов. Однако, теперь у нас появился даже ещё более модный способ обработки выбора файлов: drag and drop.

Технически это уже было возможно сделать, потому что большинство (если не все) реализации поля выбора файлов позволяли перетаскивать файлы для их выбора, но это требовало от вас показывать элемент с типом file . Итак, давайте по-настоящему использовать API, которое даёт нам браузер, для реализации выбора файлов через drag-and-drop и их загрузки на сервер.

В этой статье мы будем использовать чистый ES2015+ JavaScript (без фреймворков или библиотек) для выполнения этого проекта, и это предполагает, что у вас есть опыт работы с JavaScript в браузере. Этот пример — помимо ES2015+ синтаксиса, который можно легко изменить на синтаксис ES5 или транспилировать с помощью Babel — должен быть совместим со всеми вечнозелёными браузерами + IE 10 и 11.

Ниже можете видеть пример того, что должно получиться:

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

Первое, что мы должны обсудить, это события связанные с перетаскиванием, потому что они движущая сила этого функционала. В общем, есть восемь событий, срабатывающих в браузере и связанных с перетаскиванием: drag , dragend , dragenter , dragexit , dragleave , dragover , dragstart и drop . Мы не будем проходиться по ним всем, потому что события drag , dragend , dragexit и dragstart срабатывают на элементе, который перетаскивают, а это не наш случай, мы будем перетаскивать файлы из нашей файловой системы вместо DOM-элементов, так что эти события никогда не сработают.

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

Как и следовало ожидать, вы можете навесить обработчики для нужных событий таким же образом, каким происходит регистрация обработчиков большинства браузерных событий: с помощью addEventListener .

Ниже приведено небольшое описание того, что эти события делают. Используем dropArea из примера кода выше для того, чтобы сделать описание понятнее:

Событие dragenter — перетаскиваемый объект перетаскивается над dropArea , делая dropArea целью события drop , если пользователь перетащит его туда. Событие dragleave — перетаскиваемый объект перетащили за пределы dropArea на другой элемент, делая его целью события drop вместо dropArea . Событие dragover срабатывает каждые несколько сотен миллисекунд, пока объект перетаскивают над dropArea . Событие drop — пользователь отпустил кнопку мыши, перетаскиваемый объект перетащили на dropArea .

Стоит отметить, что при перетаскивании объекта над элементом, являющимся дочерним для dropArea , событие dragleave сработает над dropArea , а событие dragenter на дочернем элементе, потому что он становится target . Событие drop всплывёт до элемента dropArea (конечно, если до этого всплытие не остановит другой обработчик событий), таким образом событие сработает на dropArea , несмотря на то, что target у него будет другим.

До того как мы начнём добавлять функциональность drag-and-drop, нам надо добавить базовую форму со стандартным полем типа file . Технически это не обязательно, но рекомендуется предоставить такую альтернативу пользователям, чей браузер не поддерживает drag-and-drop API.

Довольно простая структура. Вы можете заметить обработчик события onchange на input . Посмотрим на него позже. Было бы также хорошей идеей добавить action к тегу form и кнопку submit , чтобы помочь людям, у которых выключен JavaScript. Затем можно использовать JavaScript для того, чтобы избавиться от них, почистить форму. В любом случае, вам понадобится серверный скрипт для загрузки файлов, неважно написан ли он собственными силами или вы используете сервис, такой как Cloudinary. Кроме этого, здесь нет ничего особенного, так что давайте набросаем стили:

Многие из этих стилей пока не используются, но это нормально. Основным моментом является то, что поле file скрыто, а его подпись label стилизована так, чтобы выглядеть как кнопка, таким образом люди поймут, что кликнув по нему вызовется диалог выбора файлов. Кроме того, мы следуем соглашению, согласно которому область, куда следует перетащить файл, обозначается пунктирной линией.

Теперь можем перейти к сладкому: drag and drop. Давайте напишем скрипт внизу страницы или в отдельном файле, смотря как вам больше нравится. Первое, что нам понадобится — это ссылка на область, куда предстоит тащить файл. Так мы сможем обрабатывать нужные нам события на ней:

Теперь давайте добавим сами события. Начнём с добавления обработчиков для всех событий, чтобы предотвратить поведение по умолчанию и остановить всплытие выше необходимого:

Мы использовали оба события dragenter и dragover для подсвечивания области для перетаскивания по причинам, о которых я говорил ранее. Если вы начинаете перетаскивать непосредственно над dropArea и затем перешли на дочерний элемент, то сработает событие dragleave и подсвечивание области пропадёт. Событие dragover сработает после событий dragenter и dragleave , так что подсветка вернётся обратно на dropArea до того, как мы увидим, что она пропала.

Мы также убираем подсветку, когда перетаскиваемый элемент покидает обозначенную область и когда его перетаскивают в неё.

Теперь всё что нам нужно, это выяснить что делать, когда файлы будут перетащены:

Код выше не приближает нас к цели, но делает две важные вещи:

  1. Демонстрирует, как получить данные о файлах, которые перетащили.
  2. Приводит нас в то же место, что и поле input с типом file и обработчиком на событие onchange : handleFiles .

Помните о том, что files это не массив, а FileList . Таким образом, при реализации handleFiles , нам нужно преобразовать FileList в массив, чтобы более легко было его итерировать:

Это было скучно (That was aniticlimactic). Перейдём к uploadFile , где будут действительно крутые штуки (real meaty stuff).

В зависимости от настроек вашего сервера, вы можете проверять различные значения status , отличные от 200 , но для наших нужд это сработает.

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

Есть несколько способов сделать это: вы можете ждать пока изображения загрузятся и запросить у сервера URL для картинок, но это означает что вам придётся ждать пока выполняется загрузка, а временами изображения могут быть довольно большими. Альтернатива, которую мы будет исследовать сегодня — это использовать FileReader API с данными файлов, которые мы получили из события drop . Это работает асинхронно, но вы можете использовать синхронную альтернативу FileReaderSync, но пользователи могут попробовать прочитать несколько больших файлов подряд, таким образом, это может заблокировать поток выполнения на длительное время и по-настоящему испортить впечатления пользователя от сервиса. Что же, давайте создадим функцию previewFile и посмотрим как это работает:

Здесь мы создали new FileReader и вызвали метод readAsDataURL для объекта File . Как уже упоминалось, это работает асинхронно, поэтому нужно добавить обработчик события onloadend для обработки результата чтения файла. После этого используем base64 URL для атрибута src нового элемента <img> и добавляем его в элемент gallery . Есть только две вещи, которые надо сделать, чтобы всё было готово и работало: добавить элемент gallery и вызов функции previewFile .

Во-первых, добавим HTML, который приведен ниже, сразу после закрывающего тега form :

Ничего особенного, это просто div . Стили уже заданы для него и изображений в нём, так что больше здесь ничего делать не надо. Теперь изменим функцию handleFiles на следующую:

Есть несколько способов сделать это, например композиция или простой колбэк forEach , в котором запускается uploadFile и previewFile , и это тоже сработает. Таким образом, когда вы перетащите или выбираете несколько изображений, они будут показаны почти мгновенно ниже формы. Интересная мысль по этому поводу: в некоторых приложениях вы можете не захотеть действительно загружать изображения на сервер, а вместо этого хранить ссылки на них в localStorage или в каком-нибудь другом кеше на стороне пользователя, чтобы приложение имело к ним доступ позже. Я лично не могу придумать хорошие сценарии использования этого, но я готов поспорить, что такие есть.

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

Если что-нибудь занимает некоторое время, индикатор прогресса помогает пользователю понять, что процесс идёт, и показывает, как долго это что-нибудь будет выполняться. Добавить индикатора прогресса довольно легко благодаря HTML5 тегу progress . Давайте начнём с добавления его в HTML-код.

Когда мы только начинаем загрузку, вызовем функцию initializeProgress для сброса состояния индикатора. Затем, с каждой выполненой загрузкой, мы вызываем функцию progressDone для увеличения числа загруженых файлов на единицу и обновления индикатора для демонстрации прогресса. Итак, добавим вызовы этих функций, обновив пару старых:

Тогда нам нужно обновить и наши функции. Переименуем progressDone в updateProgress и изменим её код как показано ниже:

Теперь initializeProgress инициализирует массив с длиной, равной numFiles , который заполнен нулями, означающими, что каждый файл загружен на 0%. В updateProgress мы видим какое из изображений обновляет свой прогресс и изменяем значение элемента с нужным индексом на предоставленный percent . Затем мы вычисляем общий процент выполнения как среднее среди всех процентов и обновляем индикатор прогресса, чтобы отобразить вычисленное значение. Мы по-прежнему вызываем initializeProgress в handleFiles также, как делали это в примере с fetch . Таким образом, всё что нам нужно, это обновить uploadFile , добавив вызов updateProgress .

Первое, что нужно отметить, это то, что мы добавили параметр i . Это индекс файла в списке файлов. Нам не нужно обновлять handleFiles для передачи этого параметра, потому что он использует forEach , который уже передаёт индекс элемента вторым параметром в колбэк. Также мы добавили слушатель события progress в xhr.upload , чтобы можно было вызвать updateProgress со значением прогресса. Объект события ( e в нашем коде) имеет два информативных поля: loaded — количество уже загруженных байтов, и total — общее количество байтов.

Выражение || 100 нужно потому, что иногда, при возникновении ошибки, e.loaded и e.total будут равны нулю, что значит, что вычисления с ними дадут NaN , таким образом 100 используется вместо отчёта о выполнении загрузки. Вы можете также использовать 0 . В любом случае ошибки будут отображаться в обработчике события readystatechange , и вы можете сообщить о них пользователю. Это сделано просто для предотвращения исключений, связанных с попытками вычислений с NaN .

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

От автора: в этом учебнике при помощи jQuery, Ajax и Php мы создадим простой загрузчик файлов в стиле Ajax. Тот, который вы легко сможете осуществить на своем сайте, дополненный серверной валидацией и валидацией на стороне клиента.

Вступление

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

загрузчик файлов ajax

скачать исходники

пример загрузчика файлов ajax


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Шаг 1: разметка HTML

Начните с создания документа html и определения формы, которая будет использоваться для загрузчика файлов. Сохраните его как index.html.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" > <link rel = "stylesheet" href = "style.css" type = "text/css" media = "screen" title = "Main" /> <script type = '' text / javascript '' src = "path/to/jquery.js" > </script> <script type = "text/javascript" src = "path/to/ajax/ajaxupload.3.5.js" > </script> <form action = "upload.php" method = "post" enctype = "multipart/form-data" > <p> <label for = "userfile" > Choose file(s) to upload: </label> <input id = "userfile" class = "input" type = "file" name = "userfile" /> </p> <div id = "loading" > <img src = "ajax-loader.jpg" alt = "Loading" /> Loading, please wait. </div>

Начинаем свой документ html с добавления обычных doctype, html, тэгов head и body. В head добавляем заголовок, ссылку на таблицу стилей, ссылку на Google jQuery CDN и свой плагин Ajax. Второй тэг script находится там, куда мы будем помещать весь код после того, как документ будет готов.

Браузер с отключенным javascript

Зависимые файлы

Нам также понадобится плагин Ajax upload. Сохраните его как ajaxupload.js и выгрузите на сервер в папку с названием "ajax".

Шаг 2: стили CSS

Шаг 3: Javascript

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

if ( ! ( extension && / ^ ( jpg | png | jpeg | gif ) $ / . test ( extension ) ) ) <

Скрипт целиком

Скопируйте и вставьте весь этот код в раздел head своего документа.

//action: 'upload.php', //выгружает отключенное в целях безопасности if ( ! ( extension && / ^ ( jpg | png | jpeg | gif ) $ / . test ( extension ) ) ) <

Шаг 4: PHP

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

$max_filesize = 2097152 ; // максимальный размер файла в БАЙТАХ. $allowed_filetypes = array ( '.jpg' , '.jpg' , '.jpg' , '.jpg' ) ; // Это будут виды файлов, которые пройдут проверку (валидацию). $filename = $_FILES [ 'userfile' ] [ 'name' ] ; // получаем название файла (включая его расширение). $ext = substr ( $filename , strpos ( $filename , '.' ) , strlen ( $filename ) - 1 ) ; // Получаем расширение из названия файла. $file_strip = str_replace ( " " , "_" , $filename ) ; //Замещаем пробелы в названии файла $upload_path = '/path/to/uploads/' ; //устанавливаем путь выгрузки

Хотя многое тут и так понятно, я поясню, что выполняет все вышеприведенное.


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Переменная $max_filesize определяет максимальный размер разрешенного для выгрузки файла, в данный момент она установлена на 2mb (так по умолчанию выставляют свои серверы большинство хостинг-провайдеров), определенные в байтах.

Переменная $allowed_filetypes выстраивает и располагает в определенном порядке виды файлов для ссылки, когда запускается проверка в нижней части кода, до которого мы вскоре доберемся.

$file_strip замещает любые пробелы в названии файла подчеркиваниями, зачем? Если имя файла используется в url, таком как ссылка на изображение и т.д., пробелы часто замещаются на 20% созданием адреса sloppy и его сложно индексировать поисковикам.

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