Источник: БЛОГ Baoyu
1. Я постепенно объясню принцип бескомпонентной загрузки на примере. Клиентский HTML выглядит следующим образом. Для просмотра загруженных вложений мы передаем элемент <input type="file">, но обязательно установите для атрибута enctype формы значение "multipart/form-data":
<form метод="post" action="upload.asp" enctype="multipart/form-data">
<метка>
<input type="file" name="file1" />
</метка>
<br />
<input type="text" name="filename" value="имя файла по умолчанию"/>
<br />
<input type="submit" value="Submit"/>
<input type="reset" value="Reset"/>
</форма>
Раньше в фоновой программе asp было очень легко получить данные ASCII, отправленные через форму. Но если вам нужно получить загруженный файл, вы должны использовать метод BinaryRead объекта Request для его чтения. Метод BinaryRead выполняет двоичное чтение указанного количества байтов из текущего входного потока. Следует отметить, что после использования метода BinaryRead коллекции Request.Form или Request.QueryString больше нельзя использовать. В сочетании со свойством TotalBytes объекта Request все данные, отправленные формой, могут быть преобразованы в двоичные файлы, но все эти данные закодированы. Во-первых, давайте посмотрим, как эти данные кодируются. Существуют ли какие-либо правила, которым следует следовать? Сегментируйте код. В коде мы преобразуем двоичный файл, считанный BinaryRead, в текст и выводим его в файл upload.asp в фоновом режиме (примечание). Не загружайте в этом примере большие файлы, иначе может произойти сбой браузера):
<%
Тусклые биданные, PostData
Размер = Запрос.TotalBytes
biData = Request.BinaryRead(Размер)
PostData = BinaryToString(biData,Size)
Response.Write "<pre>" & PostData & "</pre>" 'Используйте pre и выводите формат как есть
'Преобразуем двоичный поток в текст с помощью RecordSet
Функция BinaryToString(biData,Size)
Конст адЛонгВарЧар = 201
Установить RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, Size
RS.Открыть
RS.ДобавитьНовый
RS("mBinary").AppendChunk(biData)
RS.Обновление
BinaryToString = RS("mBinary").Значение
RS.Закрыть
Конечная функция
%>
Для простоты загрузите простейший текстовый файл (G:homepage.txt с содержимым «Baoyu: http://www.webuc.net »), чтобы проверить его. Оставьте в файле значение по умолчанию «имя файла по умолчанию». текстовое поле имя файла. Отправьте и посмотрите результат:
--------------------------------7d429871607fe.
Content-Disposition: form-data; name="file1"; filename="G:homepage.txt";
Тип контента: текстовый/обычный
Баоюй: http://www.webuc.net
--------------------------7d429871607fe
Content-Disposition: данные формы = "имя файла";
имя файла по умолчанию
-----------------------------7d429871607fe--
Видно, что для элементов в форме "----- --------------------------7d429871607fe" Такие границы используются для разделения частей на части, и в начале каждой части есть некоторая описательная информация. , например: Content-Disposition: form-data; name="filename", в информации описания вы можете узнать имя элемента формы через name="filename". Если есть контент типа filename="G:homepage.txt", это означает, что это загруженный файл. Если это загруженный файл, то в описании будет еще одна строка Content-Type: text/plain для описания. Тип содержимого файла. Информация описания и информация тела разделяются разрывами строк.
Ну, в принципе понятно. Согласно этому правилу, мы знаем, как разделять данные и обрабатывать разделенные данные. Однако мы почти упустили из виду одну проблему — граничное значение («-------» в приведенном выше примере. пример) Откуда -----------------------7d429871607fe") узнал? Это граничное значение меняется при каждой загрузке. К счастью, его можно получить с помощью Request.ServerVariables("HTTP_CONTENT_TYPE") в asp. Например, в приведенном выше примере содержимое HTTP_CONTENT_TYPE имеет вид: "multipart/form-data; border=-- --------------------------7d429871607fe", благодаря этому мы можем не только определить, является ли enctype="multipart/form-data " (если он не используется, то нет необходимости выполнять его ниже), также можно получить граничное значение border=---------------------- -----7d429871607fe. (Примечание: полученное здесь граничное значение имеет меньше «--» в начале, чем граничное значение, указанное выше. Лучше всего добавить его.)
Что касается процесса анализа данных, я не буду вдаваться в подробности. это не что иное, как использование таких функций, как InStr и Mid, для разделения нужных нам данных.
2. При загрузке порциями прогресс записи должен отражать прогресс-бар в реальном времени. Суть в том, чтобы узнать, какой объем данных получил текущий сервер в реальном времени? Возвращаясь к процессу загрузки, мы реализуем его через Request.BinaryRead(Request.TotalBytes). В процессе запроса мы не можем знать, сколько данных получил текущий сервер. Таким образом, мы можем использовать только обходной путь. Если мы сможем разделить полученные данные на части, а затем, исходя из количества загруженных блоков, мы сможем вычислить, насколько они загружены в данный момент! То есть, если 1 КБ — это 1 блок, то для получения входной поток загрузки 1 МБ будет разделен на 1024 блока. Например, если я получил 100 блоков, это означает, что было загружено 100 КБ. Когда я предложил блокировку, многим это показалось невероятным, поскольку они проигнорировали тот факт, что метод BinaryRead может не только читать указанный размер, но и читать непрерывно.
Напишите пример проверки целостности чтения блоков на основе только что приведенного примера (обратите внимание, что в этом примере не загружаются большие файлы, иначе это может привести к сбою браузера):
<%
Dim biData, PostData, TotalBytes, ChunkBytes
ChunkBytes = 1 * 1024 ' Размер чанка составляет 1 КБ.
TotalBytes = Request.TotalBytes 'Общий размер
PostData = "" ' Данные преобразуются в текстовый тип
ReadedBytes = 0 'Инициализируется значением 0
«Читайте частями»
Делать, пока ReadedBytes < TotalBytes
biData = Request.BinaryRead(ChunkBytes) 'Текущий фрагмент
PostData = PostData & BinaryToString(biData,ChunkBytes) 'Преобразуем текущий фрагмент в текст и соединяем его
ReadedBytes = ReadedBytes + ChunkBytes 'Размер чтения записи
Если ReadedBytes > TotalBytes, то ReadedBytes = TotalBytes
Петля
Response.Write "<pre>" & PostData & "</pre>" ' Используйте pre и выведите формат как есть
'Преобразуем двоичный поток в текст
Функция BinaryToString(biData,Size)
Конст адЛонгВарЧар = 201
Установить RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, Size
RS.Открыть
RS.ДобавитьНовый
RS("mBinary").AppendChunk(biData)
RS.Обновление
BinaryToString = RS("mBinary").Значение
RS.Закрыть
Конечная функция
%>
Попробуйте загрузить текстовый файл прямо сейчас. Результаты доказывают, что содержимое, прочитанное блоками, завершено, и в цикле While мы можем записывать текущий статус в приложение каждый раз, когда оно зацикливается, а затем мы можем передать Access. Приложение для динамического получения индикатора выполнения загрузки.
Также: В приведенном выше примере используется сращивание строк. Если вы хотите объединить двоичные данные, вы можете использовать метод Write объекта ADODB.Stream. Пример кода выглядит следующим образом:
Set bSourceData = createobject("ADODB.Stream" )
бSourceData.Open
bSourceData.Type = 1 'Двоичный
Делать, пока ReadedBytes < TotalBytes
biData = Request.BinaryRead(ChunkBytes)
bSourceData.Write biData ' Непосредственно используйте метод записи для записи текущего файлового потока в bSourceData.
ReadedBytes = ReadedBytes + ChunkBytes
Если ReadedBytes > TotalBytes, то ReadedBytes = TotalBytes
Приложение("ReadedBytes") = ReadedBytes
Петля
3. Сохраните загруженный файл. Получите отправленные данные через Request.BinaryRead. После разделения загруженного файла метод сохранения различается в зависимости от типа данных:
для двоичных данных вы можете сохранить двоичный поток напрямую с помощью метода SaveToFile. Объект ADODB.Stream становится файлом.
Текстовые данные можно сохранить в файл с помощью метода Write объекта TextStream.
Текстовые и двоичные данные можно легко конвертировать друг в друга. Для загрузки небольших файлов между ними практически нет разницы. Однако при сохранении между этими двумя методами все же существуют некоторые различия. Для объекта ADODB.Stream необходимо загрузить все данные, прежде чем его можно будет сохранить в виде файла. Поэтому загрузка больших файлов с использованием этого метода будет занимать много памяти. а для объекта TextStream: после создания файла вы можете записать его часть за раз и записать несколько раз. Преимущество этого в том, что он не будет занимать пространство памяти сервера. В сочетании с принципом получения данных в. блоков, проанализированных выше, мы можем записать каждую часть загруженных данных в файл middle. Я как-то провёл эксперимент и залил на ту же машину файл размером более 200 Мб. При первом методе память всё время увеличивалась. В итоге прямо подсказывало, что виртуальной памяти компьютера недостаточно. Самое обидное. даже несмотря на то, что индикатор выполнения указывает, что файл был загружен, в конечном итоге файл все равно не сохраняется. При использовании последнего метода в процессе загрузки в памяти практически не происходит изменений.
4. Нерешенные проблемы. Я видел в блоге Bestcomy, что его компонент загрузки Asp.Net может быть независим от Sever.SetTimeOut, но в Asp я не смог этого сделать. Для загрузки больших файлов я могу использовать только Server.SetTimeOut. быть установлено на очень большое значение. Я не знаю, есть ли лучшее решение.
Если мы используем метод Write объекта TextStream при сохранении файла, то если пользователь прерывает передачу файла при загрузке, часть загруженного файла все равно остается на месте. Было бы здорово, если бы загрузку можно было возобновить. Ключевая проблема заключается в том, что хотя метод Request.BinaryRead может читать блоками, он не может пропустить определенный участок чтения!
5. Заключение Принцип в основном объяснен ясно, но реальный код намного сложнее. Есть много вопросов, которые необходимо учитывать. Самая трудная часть — это анализ каждой части полученных данных. проанализировать, принадлежит ли он информации описания. Элемент формы по-прежнему является загруженным файлом, и был ли файл загружен...
Я считаю, что на основе приведенного выше описания вы также можете разработать свой собственный мощный компонент загрузки без компонентов. Я думаю, что все больше людей заботятся только о коде и не знают, как его написать самостоятельно. Может быть, у них нет времени, может быть, уровня недостаточно, и это просто вошло в привычку... У меня есть. видел слишком много технологий на CSDN Эссе из восьми частей — абзац описания, а потом весь код. Научить человека ловить рыбу не так хорошо, как научить его ловить рыбу. Если я дам вам код, вы можете не задумываться о том, почему, и просто использовать его. Когда в следующий раз вы столкнетесь с подобной проблемой, вы все равно не будете знать, почему. Я надеюсь, что эта статья поможет большему количеству людей чему-то научиться, а самое главное - что-то "просветить"!