如何将内存流作为字符串传递给 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 以作为字符串类型到达? [关闭]

如何在Nodejs中将字符串作为读取流对象传递?

将 JavaScript 变量传递给 Flask url_for

如何将json字符串传递给webmethod c# ASP.NET