【问题标题】:JavaScript Read, Process and Combine JSON from Multiple FilesJavaScript 从多个文件中读取、处理和组合 JSON
【发布时间】:2020-07-20 07:27:41
【问题描述】:

我对 JavaScript 知之甚少,但我希望上传多个 JSON 文件、处理它们、将它们转换为文本、合并它们然后下载到单个 JS 文件。

我已经设法让单个文件正常工作,但是通过将内容作为 FileReader/FileReaderSync 结果中的变量传递来处理多个文件超出了我的理解。

上传输入:
TestA.json => { "name":"John", "age":30, "car":null }
TestB.json => { "name":"Bob", "age":35, "car":"toyota"}

处理:任意....但让我们说年龄加 5

下载/输出 JS文件如下:
var TestA = { "name":"John", "age":35, "car":null }; var TestB = { "name":"Bob", "age":40, "car":"toyota"};

这是我必须处理的文件,但我不知道如何将输出合并到一个文件中;

https://jsfiddle.net/simid/0d9mqn7y/3/

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js"></script>
    <script type="text/javascript">

        function encodeJSON (varJSON) {
            //do something to varJSON
        }
        
        function processFiles() {
                var filelist = document.getElementById('files').files;
                for(var i=0; i<filelist.length; i++) {
                    encodeFiles(filelist[i]);
                }
            }
        
        function encodeFiles(file) {
            var reader = new FileReader();
            reader.onload = function() {
                var JSONData = JSON.parse(reader.result);
                encodeJSON(JSONData);
                JSONData = 'var ' + file.name.split('.')[0] + ' = ' + JSON.stringify(JSONData) + ';' 
                var blob = new Blob([JSONData], {type: "text/plain;charset=utf-8"});
                saveAs(blob, 'encoded.js');
            }
            reader.readAsText(file, "UTF-8");
        }
    </script>
</head>
<body>
    <p>JSON inputs:</p>
    <p><input type="file" multiple id="files" onchange="processFiles()" /></p>
</body>
</html>

干杯

【问题讨论】:

    标签: javascript json filereader


    【解决方案1】:

    利用 Response + async/await 和一些较新的语法可以让您走很长一段路,而无需使用回调或 FileReader。

    async function processFiles (evt) {
      // use object destructoring of evt.target 
      // instead of querying it from the DOM
      const { files } = evt.target
      let result = ''
    
      // using for..of loop instead
      for (const file of files) {
        // take advantage of the Response hack to convert
        // to json with the help of promises + await
        let json = await new Response(file).json()
        
        // modify json
    
        // append modified json to the result
        result += `var ${file.name.split('.')[0]} = ${json};\n` 
      }
    
      // save everything
      const blob = new Blob([JSONData], {type: "text/plain;charset=utf-8"})
      saveAs(blob, 'encoded.js')
    }
    

    可以使用 JSON.parse(await file.text()),但如果您可以从响应中获取 json 并且有更多跨浏览器支持,为什么还要麻烦?

    【讨论】:

    • 为将我送入兔子洞而欢呼。较新的语法对我来说很陌生,但我很想了解它。在我的页面中交换 JS 会产生 Uncaught (in promise) TypeError: Cannot read property 'target' of undefined 你能给我一个正确的方向吗?
    • 更改onchange="processFiles()" -> onchange="processFiles(event)"
    • 或者使用input.onchange = processFile添加带有js的事件监听器
    • 太棒了。谢谢你。我必须 result += `var ${file.name.split('.')[0]} = ${JSON.stringify(json)};\n` 现在去玩弄看看它是如何工作的。
    【解决方案2】:

    这将在第一个文件处理完毕后立即触发 reader.readAsText(),因此您只会得到第一个文件。

    您可以通过在循环外创建一个全局变量来解决此问题。

    这应该可以工作,注意letfor 循环中的使用:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>    
        <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js"></script>
        <script type="text/javascript">
    
          var JSONData = "";
    
          function encodeJSON(file, t) {
            JSONData += 'var ' + file.name.split('.')[0] + ' = ' + t.result + '\n';
          }
    
          function processFiles() {
            var filelist = document.getElementById('files').files;
              var reader = new FileReader();
              reader.onload = function(e) {
                for(let i=0; i<filelist.length; i++) {
                  encodeJSON(filelist[i], e.target)
              }
              var blob = new Blob([JSONData], {type: "text/plain;charset=utf-8"});
              saveAs(blob, 'encoded.js');
            }
            reader.readAsText(filelist[0], 'UTF-8')
          }
      </script>
    </head>
    <body>
        <p>JSON inputs:</p>
        <p><input type="file" multiple id="files" onchange="processFiles()" /></p>
    </body>
    </html>
    

    【讨论】:

    • 你不想每次迭代都触发saveAs
    • 问题是你还是只读取一个文件filelist[0]
    • 不,它会生成一个组合文件。你可以打电话给reader.readAsText(filelist[filelist.length -1], 'UTF-8'),结果是一样的。
    • 感谢休的帮助。虽然它似乎适用于小型 JSON 样本,但我有非常大的 JSON 文件需要存储在带有 JSON.Parse 的变量中,以便可以使用一些循环和逻辑对其进行修改。当我上传 2 个文件(第一个小文件,第二个大文件)时,输出似乎变得混乱,列表中第一个文件的 JSON 似乎处理了两次。结果导出的第一个文件有两次?
    • @Endless 的好解决方案
    【解决方案3】:

    已解决 - 谢谢@Endless .. 这就是我的结果;

    <!DOCTYPE html>
    <html>
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>    
        <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js"></script>
        <script type="text/javascript">
    
        function encodeJSON (varJSON) {
            // do something to varJSON
        }
    
        async function processFiles (evt) {
            // use object destructoring of evt.target 
            // instead of querying it from the DOM
            const { files } = evt.target
            let result = ''
    
            // using for..of loop instead
            for (const file of files) {
                // take advantage of the Response hack to convert
                // to json with the help of promises + await
                let json = await new Response(file).json()
                
                // modify json
                encodeJSON(json);
    
                // append modified json to the result
                result += \`var ${file.name.split('.')[0]} = ${JSON.stringify(json)};\n\` 
            }
    
            // save everything
            const blob = new Blob([result], {type: "text/plain;charset=utf-8"})
            saveAs(blob, 'encoded.js')
        }
    
        </script>
    </head>
    <body>
        <p>JSON inputs:</p>
        <p><input type="file" multiple id="files" onchange="processFiles(event)" /></p>
    </body>
    </html>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 1970-01-01
      • 2014-04-24
      • 1970-01-01
      相关资源
      最近更新 更多