首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从客户端和客户端读取超过javascript中单个字符串最大大小的文本文件

从客户端和客户端读取超过javascript中单个字符串最大大小的文本文件
EN

Stack Overflow用户
提问于 2018-06-22 13:14:47
回答 1查看 194关注 0票数 1

我想用javascript反向执行以下在客户端执行的步骤,但我在使用blob时遇到了问题。

在indexedDB数据库中,位于对象存储索引上的开放游标上:

使用JSON字符串的JSON.stringify.

  • Made新blob { type:'text/csv‘},
  1. 将数据对象从文本对象提取到字符串。
  2. 将blob写入数组。
  3. 将光标下移一次,并从第1步重复。

事务成功完成后,将从blob数组创建一个相同类型的新blob。

这样做的原因是JSON字符串的连接超过了单个字符串的最大允许大小;因此,不能先连接并生成一个大字符串的blob。但是,可以将斑点阵列制作成更大的单个斑点,大约350MB,并下载到客户机盘上。

为了逆转这个过程,我想我可以读入blob,然后将其分成组件blob,然后将每个blob作为字符串读取;但我不知道如何做到这一点。

如果将FileReader读取为文本,则结果是一个很大的文本块,该文本块无法写入单个变量,因为它超过了最大大小并引发分配大小溢出错误。

将文件作为数组缓冲区读取似乎是一种允许将blob分成片的方法,但似乎存在某种编码问题。

有没有一种方法可以将原始的过程按原样逆转,或者可以添加一个编码步骤,允许数组缓冲区转换回原始字符串?

我试着阅读了一些看起来相关的问题,但在这一点上,我不理解他们正在讨论的编码问题。似乎恢复一个字符串是相当复杂的。

感谢您能提供的任何指导。

采用accepted 之后的附加信息

当然,我的代码并没有什么特别之处,但我想把它分享给那些像我一样新手的人。这是集成到asnyc函数中的公认答案,用于读取blobs、解析它们并将它们写入数据库。

这种方法使用的内存非常少。太糟糕了,没有一种方法可以将数据写入磁盘。在将数据库写入磁盘时,内存使用量会随着大blob的生成而增加,然后在下载完成后不久释放。使用此方法从本地磁盘上传文件,似乎无需在切片之前将整个blob加载到内存中。这就好像文件是以分片的形式从磁盘中读取的。因此,它在内存使用方面非常有效。

在我的特定情况下,仍然有工作要做,因为使用它将总计350MB的50,000个JSON字符串写回数据库相当慢,大约需要7:30才能完成。

现在,每个单独的字符串被单独分割,作为文本读取,并在单个事务中写入数据库。将blob分成由一组JSON字符串组成的更大的片段,将它们作为块中的文本读取,然后在单个事务中将它们写入数据库,是否会在不使用大量内存的情况下执行得更快,这是我需要进行实验的内容,也是另一个问题的主题。

如果使用替代循环来确定填充大小const c所需的JSON字符串的数量,然后对该大小的blob进行切片,将其作为文本读取,并将其拆分以解析每个单独的JSON字符串,则对于c =250,000到1,000,000,完成操作的时间大约为1:30。无论如何,解析大量JSON字符串似乎仍然会减慢速度。大的blob切片不会转换为作为单个块解析的大量文本,50,000个字符串中的每一个都需要单独解析。

代码语言:javascript
复制
   try

     {

       let i, l, b, result, map, p;

       const c = 1000000;


       // First get the file map from front of blob/file.

       // Read first ten characters to get length of map JSON string.

       b = new Blob( [ f.slice(0,10) ], { type: 'text/csv' } ); 

       result = await read_file( b );

       l = parseInt(result.value);


       // Read the map string and parse to array of objects.

       b = new Blob( [ f.slice( 10, 10 + l) ], { type: 'text/csv' } ); 

       result = await read_file( b );

       map = JSON.parse(result.value); 


       l = map.length;

       p = 10 + result.value.length;


       // Using this loop taks about 7:30 to complete.

       for ( i = 1; i < l; i++ )

         {

           b = new Blob( [ f.slice( p, p + map[i].l ) ], { type: 'text/csv' } ); 

           result = await read_file( b ); // FileReader wrapped in a promise.

           result = await write_qst( JSON.parse( result.value ) ); // Database transaction wrapped in a promise.

           p = p + map[i].l;

           $("#msg").text( result );

         }; // next i


       $("#msg").text( "Successfully wrote all data to the database." );


       i = l = b = result = map = p = null;

     }

   catch(e)

     { 

       alert( "error " + e );

     }

   finally

     {

       f = null;

     }



/* 

  // Alternative loop that completes in about 1:30 versus 7:30 for above loop.


       for ( i = 1; i < l; i++ )

         { 

           let status = false, 

               k, j, n = 0, x = 0, 

               L = map[i].l,

               a_parse = [];



           if ( L < c ) status = true;

           while ( status )

             {

               if ( i+1 < l && L + map[i+1].l <= c ) 

                 {

                   L = L + map[i+1].l;

                   i = i + 1;

                   n = n + 1;

                 }

               else

                 {

                   status = false;

                 };

             }; // loop while


           b = new Blob( [ f.slice( p, p + L ) ], { type: 'text/csv' } ); 

           result = await read_file( b ); 

           j = i - n; 

           for ( k = j; k <= i; k++ )

             {

                a_parse.push( JSON.parse( result.value.substring( x, x + map[k].l ) ) );

                x = x + map[k].l;

             }; // next k

           result = await write_qst_grp( a_parse, i + ' of ' + l );

           p = p + L;

           $("#msg").text( result );

         }; // next i



*/



/*

// Was using this loop when thought the concern may be that the JSON strings were too large,
// but then realized the issue in my case is the opposite one of having 50,000 JSON strings of smaller size.

       for ( i = 1; i < l; i++ )

         {

           let x,

               m = map[i].l,

               str = [];

           while ( m > 0 )

             {

               x = Math.min( m, c );

               m = m - c;

               b = new Blob( [ f.slice( p, p + x ) ], { type: 'text/csv' } ); 

               result = await read_file( b );

               str.push( result.value );

               p = p + x;

             }; // loop while


            result = await write_qst( JSON.parse( str.join("") ) );

            $("#msg").text( result );

            str = null;

         }; // next i
*/           
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-22 14:44:30

有趣的是,你已经在你的问题中说了应该做什么:

切片您的斑点。

Blob接口确实有一个.slice()方法。

但是要使用它,你应该跟踪你的合并发生的位置。(可以在数据库的其他字段中,甚至可以作为文件的标题:

代码语言:javascript
复制
function readChunks({blob, chunk_size}) {
  console.log('full Blob size', blob.size);
  const strings = [];  
  const reader = new FileReader();
  var cursor = 0;
  reader.onload = onsingleprocessed;
  
  readNext();
  
  function readNext() {
    // here is the magic
    const nextChunk = blob.slice(cursor, (cursor + chunk_size));
    cursor += chunk_size;
    reader.readAsText(nextChunk);
  }
  function onsingleprocessed() {
    strings.push(reader.result);
    if(cursor < blob.size) readNext();
    else {
      console.log('read %s chunks', strings.length);
      console.log('excerpt content of the first chunk',
        strings[0].substring(0, 30));
    }
  }
}



// we will do the demo in a Worker to not kill visitors page
function worker_script() {
  self.onmessage = e => {
    const blobs = [];
    const chunk_size = 1024*1024; // 1MB per chunk
    for(let i=0; i<500; i++) {
      let arr = new Uint8Array(chunk_size);
      arr.fill(97); // only 'a'
      blobs.push(new Blob([arr], {type:'text/plain'}));
    }
    const merged = new Blob(blobs, {type: 'text/plain'});
    self.postMessage({blob: merged, chunk_size: chunk_size});
  }
}
const worker_url = URL.createObjectURL(
  new Blob([`(${worker_script.toString()})()`],
    {type: 'application/javascript'}
  )
);
const worker = new Worker(worker_url);
worker.onmessage = e => readChunks(e.data);
worker.postMessage('do it');

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50981075

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档