如何将内存流作为字符串传递给 javascript
Posted
技术标签:
【中文标题】如何将内存流作为字符串传递给 javascript【英文标题】:How to pass a memory stream to javascript as a string 【发布时间】:2021-12-26 20:51:52 【问题描述】:我正在使用 MemoryStream 安装一个 zip 文件。
我知道如何使用回发下载此文件。
但我想将内存流的内容传递给回调并以 javascript 代码下载。
当我尝试执行此操作时,会发生 zip 文件以正确的大小可供下载,并且其中的文件列表正确,包括名称,但文件无效,它们看起来像 0 的空文件% 压缩率。
我认为我最大的问题是在尝试将 MemoryStream 内容转换为字符串时,此时或在 javascript 中的文件下载功能中肯定有一些错误。
如果有人可以就如何将文件流式传输到 javascript 并下载它提供任何提示,我将不胜感激。
放弃在磁盘上创建 zip 文件的选项。
使用的转换代码:
> lCallBackResult.htmlCode = Encoding.ASCII.GetString(lMemoryStream.ToArray());
下载使用的代码(javascript):
> DOWFileWND(lFileName, 'text/zip', pCallbackResult.htmlcode);
> function DOWFileWND (pFileName, pFileType, pContent)
>
> let lData = new Blob([pContent], type: pFileType );
>
> //Verifica o navegador
> if (window.navigator && window.navigator.msSaveOrOpenBlob)
>
> //For IE
> window.navigator.msSaveOrOpenBlob(lData, pFileName);
>
> else
>
> //Cria o link
> let lLink = document.createElement("a");
> //Adiciona o link no documento
> document.body.appendChild(lLink);
> //Esconde o link
> lLink.style = "display: none";
>
> //Cria a url
> let lUrl = URL.createObjectURL(lData);
> //Seta o endereço do link
> lLink.href = lUrl;
> //Seta o nome do arquivo
> lLink.download = pFileName;
> //Dispara o link
> lLink.click();
> //Deleta o link
> URL.revokeObjectURL(lLink.href);
> //Remove o link
> lLink.remove();
> ;
Zip 创建代码 (C#):
private TCallbackResult CALLExportDOC(TCallbackArgument pCallBackArgument)
//Cria a isntância dos componentes
DTSTreeView lDTSTreeView = new DTSTreeView();
tabTreeViewTableAdapter ltabTreeView = new tabTreeViewTableAdapter();
//Cria os parâmetros de retorno
TCallbackResult lCallBackResult = new TCallbackResult();
//Pega a referência do item
TTreeItemData lTreeItemData = new TTreeItemData(FValue);
//Seta as propriedades
lCallBackResult.Sender = pCallBackArgument.Sender;
lCallBackResult.Value = pCallBackArgument.Value;
lCallBackResult.SubValue = pCallBackArgument.SubValue;
//Armazena o path do arquivo
string lDocPath = "";
//Cria o stream de memória
MemoryStream lMemoryStream = new MemoryStream();
//Cria o arquivo zip
ZipOutputStream lZipOutputStream = new ZipOutputStream(lMemoryStream);
//Cria o buffer
byte[] lBuffer = new byte[4096];
//0-9, 9 being the highest compression
lZipOutputStream.SetLevel(9);
//Executa a procedure
ltabTreeView.spn_EXPDocument(lDTSTreeView.tabTreeView, lTreeItemData.IdAmb, lTreeItemData.IdPar, lTreeItemData.IdCur, 0, 1, true, true);
//Gera o zip do diretório--------------------------------------------------------------------------------------------------------------------
try
//Roda em todos os itens retornados
foreach (DTSTreeView.tabTreeViewRow lCurrentRow in lDTSTreeView.tabTreeView.Rows)
//Armazena a versão e extensão
int lVersion_Doc = Convert.ToInt32(lCurrentRow.data_trv.Split('.')[0]);
string lExtension_Doc = lCurrentRow.data_trv.Split('.')[1];
//Armazena a versão do arquivo
string lVersion_Fix = (lVersion_Doc < 10) ? "0" + lVersion_Doc.ToString() : lVersion_Doc.ToString();
//Cria a entrada no zip
ZipEntry lZipEntry = new ZipEntry(Path.GetFileName(TFileInfo.CONVERTToFileName(lCurrentRow.descr_trv) + "_AV" + lVersion_Fix + "." + lExtension_Doc));
//Seta a data da entrada
lZipEntry.DateTime = DateTime.Now;
//Vai para a próxima entrada
lZipOutputStream.PutNextEntry(lZipEntry);
//Seta o diretório correto do arquivo
lDocPath = Paths.DOCFisicalPath(lCurrentRow.idcurrent_trv);
//Abre o arquivo
using (FileStream lFileStream = File.OpenRead(lDocPath + lCurrentRow.idcurrent_trv.ToString() + "v" + lCurrentRow.data_trv))
//Declara a variavel
int lSourceBytes;
//Roda no arquivo inteiro
do
//Armazena o tamanho do arquivo
lSourceBytes = lFileStream.Read(lBuffer, 0, lBuffer.Length);
//Grava no arquivo zip
lZipOutputStream.Write(lBuffer, 0, lSourceBytes);
while (lSourceBytes > 0);
//Fecha o arquivo zip
lZipOutputStream.Finish();
lZipOutputStream.Close();
//Armazena o nome do elemento
string lDescription = GETDescription(lTreeItemData) + ".zip";
//Limpa o nome do arquivo
lDescription = TFileInfo.CONVERTToFileName(lDescription);
//Seta o retorno
lCallBackResult.Value = lDescription;
lCallBackResult.HtmlCode = Encoding.ASCII.GetString(lMemoryStream.ToArray());
catch
//Fecha o arquivo zip
lZipOutputStream.Finish();
lZipOutputStream.Close();
//Retorna o valor
return lCallBackResult;
【问题讨论】:
在 C# 端使用 Convert.ToBase64String,然后调整您的 javascript 以将该 base64 字符串转换为 blob。使用 ascii 或任何其他文本编码将二进制数据表示为字符串并不是一个好主意。 我是怎么做到的? C# 部分没问题,但在 javascript 中如何将该 base64 字符串转换为 blob? 写入内存流后,您必须在读取之前将位置设置为零。 感谢您的周到回答,但您的回答并没有帮助我解决问题,我需要您告诉我如何去做。 【参考方案1】:C#代码:
lCallBackResult.HtmlCode = Convert.ToBase64String(lMemoryStream.ToArray());
Javascript 代码(直接):
const lByteCharacters = atob(pCallbackResult.htmlcode);
const lByteNumbers = new Array(lByteCharacters.length);
for (let i = 0; i < lByteCharacters.length; i++)
lByteNumbers[i] = lByteCharacters.charCodeAt(i);
const lByteArray = new Uint8Array(lByteNumbers);
DOWFileWND(lFileName, 'application/zip', lByteArray);
Javascript 代码调用者(切片):
let lBlob = ConvertBase64toBlob(pCallbackResult.htmlcode, 'application/zip', 512);
DOWBlobWND(lFileName, lBlob);
Javascript 代码函数(切片):
function ConvertBase64toBlob(b64Data, contentType, sliceSize)
contentType = contentType || ''; sliceSize = sliceSize || 512;
let byteCharacters = atob(b64Data);
let byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize)
let slice = byteCharacters.slice(offset, offset + sliceSize);
let byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++)
byteNumbers[i] = slice.charCodeAt(i);
let byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
let blob = new Blob(byteArrays, type: contentType);
return blob;
【讨论】:
以上是关于如何将内存流作为字符串传递给 javascript的主要内容,如果未能解决你的问题,请参考以下文章
Javascript:通过将路径作为字符串传递给对象来从对象中获取深层价值[重复]
如何将 PHP 字符串传递给 Javascript 函数调用? [复制]
如何将 mysql 数字类型数据从 php 传递到 Javascript 以作为字符串类型到达? [关闭]