Fonte: Baoyu BLOG
1. Explicarei o princípio do upload sem componentes pouco a pouco com um exemplo. O HTML do cliente é o seguinte. Para navegar pelos anexos enviados, passamos o elemento <input type="file">, mas certifique-se de definir o atributo enctype do formulário como "multipart/form-data":
<form method="post" action="upload.asp" enctype="multipart/form-data">
<rótulo>
<input type="arquivo" nome="arquivo1" />
</label>
<br />
<input type="text" name="nome do arquivo" value="nome do arquivo padrão"/>
<br />
<input type="submit" value="Enviar"/>
<input type="reset" value="Redefinir"/>
</form>
No programa asp em segundo plano, costumava ser muito fácil obter os dados ASCII enviados pelo formulário. Mas se você precisar obter o arquivo carregado, deverá usar o método BinaryRead do objeto Request para lê-lo. O método BinaryRead executa a leitura binária de um número especificado de bytes do fluxo de entrada atual. Uma coisa a ser observada é que, uma vez usado o método BinaryRead, as coleções Request.Form ou Request.QueryString não poderão mais ser usadas. Combinado com a propriedade TotalBytes do objeto Request, todos os dados enviados pelo formulário podem ser convertidos em binários, mas esses dados são todos codificados. Primeiro, vamos dar uma olhada em como esses dados são codificados. Existe alguma regra a seguir? Segmente o código. No código, convertemos o binário lido por BinaryRead em texto e o enviamos em upload.asp em segundo plano. Não carregue arquivos grandes neste exemplo, caso contrário o navegador poderá travar):
<%
Dim biData, PostData
Tamanho = Solicitação.TotalBytes
biData = Request.BinaryRead(Tamanho)
PostData = BinaryToString(biData,Tamanho)
Response.Write "<pre>" & PostData & "</pre>" 'Use pré e produza o formato como está
'Converta o fluxo binário em texto com a ajuda do RecordSet
Função BinaryToString(biData,Tamanho)
Const adLongVarChar = 201
Definir RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, Tamanho
RS.Aberto
RS.AdicionarNovo
RS("mBinário").AppendChunk(biData)
RS.Atualização
BinaryToString = RS("mBinário").Valor
RS.Fechar
Função final
%>
Para simplificar, carregue o arquivo de texto mais simples (G:homepage.txt, com o conteúdo "Baoyu: http://www.webuc.net ") para testá-lo. Mantenha o valor padrão "default filename" no arquivo. nome do arquivo da caixa de texto Envie e veja a saída:
--------------------------------7d429871607fe.
Disposição do conteúdo: form-data name="file1";
Tipo de conteúdo: texto/simples
Baoyu: http://www.webuc.net
--------------------------7d429871607fe
Disposição do conteúdo: nome-dados do formulário = "nome do arquivo"
nome de arquivo padrão
-----------------------------7d429871607fe--
Pode-se observar que para os itens no formulário, "----- --------------------------7d429871607fe" Tais limites são usados para separar peças em peças, e há algumas informações descritivas no início de cada peça , por exemplo: Content- Disposition: form-data; nome do arquivo = "nome do arquivo", nas informações de descrição você pode saber o nome do item do formulário através de nome = "nome do arquivo". Se houver conteúdo como filename="G:homepage.txt", significa que é um arquivo enviado. Se for um arquivo enviado, as informações de descrição terão mais uma linha Content-Type: text/plain para descrever. o tipo de conteúdo do arquivo. As informações de descrição e as informações do corpo são separadas por quebras de linha.
Bem, está basicamente claro. De acordo com esta regra, sabemos como separar os dados e processar os dados separados. No entanto, quase ignoramos um problema, que é o valor limite ("-------" acima. exemplo) Como -----------------------7d429871607fe") sabia? Este valor limite é diferente toda vez que você faz upload. Felizmente, ele pode ser obtido por meio de Request.ServerVariables("HTTP_CONTENT_TYPE") em asp. border=-- --------------------------7d429871607fe", com isso, não podemos apenas determinar se enctype="multipart/form-data "(se não for usado, não há necessidade de executá-lo abaixo), você também pode obter o valor limite limit=---------------------- ----- 7d429871607fe. (Nota: O valor limite obtido aqui tem menos "-" no início do que o valor limite acima. É melhor adicioná-lo.)
Quanto ao processo de análise dos dados, não entrarei em detalhes. nada mais é do que usar funções como InStr e Mid para separar os dados que desejamos.
2. Ao fazer upload em blocos, o progresso do registro deve refletir a barra de progresso em tempo real. A essência é saber quantos dados o servidor atual obteve em tempo real. Pensando no processo de upload, implementamos-o através de Request.BinaryRead(Request.TotalBytes). Durante o processo de solicitação, não podemos saber quantos dados o servidor atual obteve. Portanto, só podemos usar uma solução alternativa se pudermos dividir os dados obtidos em partes e, com base no número de blocos que foram carregados, podemos calcular o tamanho do upload atual! Ou seja, se 1K for 1 bloco, o fluxo de entrada de upload de 1 MB será dividido em 1.024 blocos para obter. Por exemplo, se eu obtive 100 blocos, significa que 100K foram carregados. Quando propus o bloqueio, muitas pessoas acharam incrível porque ignoraram que o método BinaryRead pode não apenas ler o tamanho especificado, mas também ler continuamente.
Escreva um exemplo para verificar a integridade da leitura do bloco, com base no exemplo agora (observe que este exemplo não carrega arquivos grandes, caso contrário, pode causar falha no navegador):
<%
Dim biData, PostData, TotalBytes, ChunkBytes
ChunkBytes = 1 * 1024 ' O tamanho do pedaço é 1K
TotalBytes = Request.TotalBytes 'Tamanho total
PostData = "" 'Dados convertidos para tipo texto
ReadedBytes = 0 'Inicializado com 0
'Leia em pedaços
Faça enquanto ReadedBytes <TotalBytes
biData = Request.BinaryRead(ChunkBytes) 'Pedaço atual
PostData = PostData & BinaryToString(biData,ChunkBytes) 'Converta o pedaço atual em texto e divida-o
ReadedBytes = ReadedBytes + ChunkBytes 'Tamanho de leitura do registro
Se ReadedBytes > TotalBytes Então ReadedBytes = TotalBytes
Laço
Response.Write "<pre>" & PostData & "</pre>" 'Use pré e produza o formato como está
' Converte fluxo binário em texto
Função BinaryToString(biData,Tamanho)
Const adLongVarChar = 201
Definir RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, Tamanho
RS.Aberto
RS.AdicionarNovo
RS("mBinário").AppendChunk(biData)
RS.Atualização
BinaryToString = RS("mBinário").Valor
RS.Fechar
Função final
%>
Tente fazer upload do arquivo de texto agora mesmo. Os resultados de saída provam que o conteúdo lido nos blocos está completo e, no loop While, podemos registrar o status atual no aplicativo toda vez que ele faz o loop e então podemos passar o acesso ao. Aplicativo para obter dinamicamente a barra de progresso do upload.
Além disso: no exemplo acima, a emenda de string é usada. Se você deseja unir dados binários, você pode usar o método Write do objeto ADODB.Stream. O código de exemplo é o seguinte:
Set bSourceData = createobject("ADODB.Stream" )
bSourceData.Open
bSourceData.Type = 1 'Binário
Faça enquanto ReadedBytes <TotalBytes
biData = Solicitação.BinaryRead(ChunkBytes)
bSourceData.Write biData 'Usa diretamente o método write para gravar o fluxo de arquivo atual em bSourceData
ReadedBytes = ReadedBytes + ChunkBytes
Se ReadedBytes > TotalBytes Então ReadedBytes = TotalBytes
Aplicativo("ReadedBytes") = ReadedBytes
Laço
3. Salve o arquivo carregado. Obtenha os dados enviados por meio de Request.BinaryRead. Após separar o arquivo carregado, o método de salvamento é diferente dependendo do tipo de dados:
para dados binários, você pode salvar o fluxo binário diretamente por meio do método SaveToFile. Objeto ADODB.Stream Torne-se um arquivo.
Para dados de texto, você pode salvar os dados de texto em um arquivo por meio do método Write do objeto TextStream.
Dados de texto e dados binários podem ser facilmente convertidos entre si. Para fazer upload de arquivos pequenos, basicamente não há diferença entre os dois. No entanto, ainda existem algumas diferenças ao salvar entre os dois métodos. Para o objeto ADODB.Stream, todos os dados devem ser carregados antes de serem salvos como um arquivo. Portanto, o upload de arquivos grandes usando este método ocupará muita memória. e para o objeto TextStream, após a criação do arquivo, você pode gravar parte dele por vez e gravá-lo várias vezes. A vantagem disso é que não ocupará o espaço de memória do servidor. blocos analisados acima, podemos gravar cada parte dos dados carregados no meio do arquivo. Certa vez, fiz um experimento e carreguei um arquivo de mais de 200 MB na mesma máquina. Usando o primeiro método, a memória continuou aumentando. No final, a memória virtual do computador era insuficiente. mesmo que a barra de progresso indique que o arquivo foi carregado, no final, o arquivo ainda não foi salvo. Usando o último método, basicamente não há alteração na memória durante o processo de upload.
4. Problemas não resolvidos Vi Bestcomy no blog descrevendo que seu componente de upload do Asp.Net pode ser independente do Sever.SetTimeOut, mas no Asp não consegui fazer isso. Para fazer upload de arquivos grandes, só consigo usar o Server.SetTimeOut. ser definido com um valor muito grande. Não sei se existe uma solução melhor.
Se usarmos o método Write do objeto TextStream ao salvar um arquivo, se o usuário interromper a transferência do arquivo durante o upload, a parte do arquivo que foi enviada ainda estará lá. Seria ótimo se o upload pudesse ser retomado. O principal problema é que embora o método Request.BinaryRead possa ler em blocos, ele não pode pular uma determinada seção da leitura!
5. Conclusão O princípio é basicamente explicado de forma clara, mas o código real é muito mais complicado do que isso. A parte mais problemática é a análise dos dados adquiridos. analise se ele pertence às informações de descrição. O item do formulário ainda é um arquivo carregado e se o arquivo foi carregado...
Acredito que com base na descrição acima, você também pode desenvolver seu próprio componente de upload sem componentes poderoso. Acho que mais pessoas só se preocupam com o código e não sabem como escrevê-lo sozinhas. Talvez não tenham tempo, talvez o nível não seja suficiente e mais disso tenha se tornado um hábito... eu tenho. vi muitas tecnologias no CSDN Ensaio de oito partes - um parágrafo de descrição e depois todo o código. Ensinar um homem a pescar não é tão bom quanto ensiná-lo a pescar. Se eu lhe der um código, você pode não pensar no porquê e simplesmente usá-lo. Quando encontrar um problema semelhante na próxima vez, você ainda não saberá o porquê. Espero que este artigo possa ajudar mais pessoas a aprender alguma coisa, e o mais importante é “esclarecer” alguma coisa!