将Excel转换为JSON-使用React-Dropzone可能是客户端

问题描述

这类似于问题:Excel to JSON javascript code?,但使用React和Dropzone。

我要么需要将Excel文件上传到服务器并在服务器上解析,要么需要在浏览器中将其解析为JSON,然后上传JSON。

我写了React(前端)和Server(后端)来处理CSV文件并将其存储到MongoDB。反应面在下面。

我的两个问题是:

  1. 如果在客户端执行此操作,如何使用XSLX或sheetjs读取和处理使用DropZone删除文件

  2. 如果我在服务器上执行此操作,如何正确上传Excel文件(我读过有关为Office / Excel设置Mime-Extension的文章)。我已经能够上传文件,但是上传之后我再也无法在Excel中打开它。它的大小通常是原来的两倍,可能会发生UTF-8到UTF-16的转换。

    import React,{useCallback,useState} from 'react';
    import {useDropzone} from 'react-dropzone'  // use hooks 
    import Dropzone from 'react-dropzone'  
    import XLSX from 'xlsx' 
    //import logo1 from './logo.svg';    // original 
    import logo2 from './images/ShedMadeOfWood_small.jpg';  // demo logo 
    import './App.css'; 
    
    
    function App() {
      // Edit <code>src/App.js</code> and save to reload.
      // const [files,setFiles] = useState([])
      const currDateTime1 = new Date().toISOString()
      console.warn(currDateTime1 + " Starting React/App: function App()")
      const onDrop = useCallback(acceptedFiles => {
        // Do something with the files 
        const currDateTime2 = new Date().toISOString()
        console.log(currDateTime2 + " trying to read file")
        acceptedFiles.forEach((file) => {
          const reader = new FileReader() 
          reader.onabort = () => console.log('file reading was aborted')
          reader.onerror = () => console.log('file reading has Failed')
          reader.onload = (data) => {
               // Do what you want with the file contents 
               //console.log("file size:",data.length);
               //const binaryStr = reader.result 
               //const fileContents = reader.readAsText
               const fileContents = data.target.result 
               const currDateTime3 = new Date().toISOString()
               console.log(currDateTime3 + " Text print of file contents:")
               // console.log(fileContents)
    
               // This fetch worked for CSV file      
                   
                   fetch('http://localhost:3001/api/filedata',{
                      method: 'POST',headers: {
                         'Accept': 'application/json','Content-Type': 'application/json'
                      },// Todo - Could add userid,datetime here,filename,etc...  
                      body: JSON.stringify({
                         "fileContents": fileContents
                         //,secondParam: 'yourOtherValue',})
                    })
                    
                    // another example passed formData to the body: https://stackoverflow.com/questions/41025078/react-dropzone-how-to-upload-image
                    /* 
                    fetch('http://localhost:3001/api/filedatabinary',body: fileContents
                      })
                    */
        
        
                }
              reader.readAsText(file)
              //reader.readAsBinaryString(file)
             
            })
          },[])
          const {getRootProps,getInputProps,isDragActive} = useDropzone ({onDrop}) 
          const [fileNames,setFileNames] = useState([]);
          const handleDrop = acceptedFiles =>
            setFileNames(acceptedFiles.map(file => file.name));
        
          return (
            <div align="center">
              <div className="App" {...getRootProps()}>
                <header className="App-header">
                  <img src={logo2} className="App-logo" alt="logo" />
                </header>
                <h4>CSV Files here</h4>
                <input {...getInputProps()} />
                {
                  isDragActive ? 
                    <p>Drop the files here ...</p> : 
                    <div>
                      <p>Drag and Drop a csv file here,<br />
                      or click to select files.</p>
                    </div>
                }
              </div>
              <h4>Drop Excel Files Here</h4>
              <Dropzone onDrop={handleDrop}>
                {({ getRootProps,getInputProps }) => (
                  <div {...getRootProps({ className: "dropzone" })}>
                    <input {...getInputProps()} />
                    <p>Drag and drop Excel files,or click to select files</p>
                  </div>
                )}
              </Dropzone>
              <div>
                <strong>Excel File(s):</strong>
                <ul>
                  {fileNames.map(fileName => (
                    <li key={fileName}>{fileName}</li>
                  ))}
                </ul>
              </div>
              <hr />
                <br /><br />
                Thanks for using our company!
            </div>
            
              );
        }
        
        export default App;

我的服务器端代码拆分并循环遍历CSV的各行,并将它们作为JSON保存到MongoDB。我将CSV文件内容作为JSON变量的单个值上传,然后在服务器上解析。我最近的更改是使用两种不同的技术添加了两个放置区,一个用于CSV,一个用于Excel。我可以在服务器上使用两种不同的REST方法,一种用于CSV,另一种用于二进制(如果需要)。或者,我可以在客户端上转换为JSON,而在服务器上只有一种REST方法

解决方法

基于此帖子Parse XLSX with Node and create json,让XLSX在客户端上工作。

换句话说,浏览器端将Excel转换为JSON,并将JSOn发布到服务器。我假设只有一个工作表,并且仅在有多个工作表时才转换第一个工作表。

我不确定他为什么同时需要两种类型的readAsBinaryString和readAsArrayBuffer,但效果很好。

  const handleExcelDrop = (acceptedFiles) => {
    console.log("handleExcelDrop")
    setFileNames(acceptedFiles.map(file => file.name));
     acceptedFiles.forEach((file) => {
        console.log("handleExcelDrop:forEach(file)")
        // See https://stackoverflow.com/questions/30859901/parse-xlsx-with-node-and-create-json 
        const reader = new FileReader() 
        const rABS = !!reader.readAsBinaryString;  // !! converts object to boolean 
        reader.onabort = () => console.log('file reading was aborted')
        reader.onerror = () => console.log('file reading has failed')
        reader.onload = (e) => {
            // Do what you want with the file contents 
            var bstr = e.target.result; 
            var workbook = XLSX.read(bstr,{ type: rABS ? "binary" : "array" })
            var sheet_name_list = workbook.SheetNames[0];
            var jsonFromExcel = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list],{
                raw: false,dateNF: "MM-DD-YYYY",header:1,defval: ""
            })
            console.log("jsonFromExcel object=")
            console.log(jsonFromExcel)
            console.log("jsonFromExcel string=")
            console.log(JSON.stringify(jsonFromExcel))

            fetch('http://localhost:3001/api/filedataExcel',{
              method: 'POST',headers: {
                 'Accept': 'application/json','Content-Type': 'application/json'
              },// TODO - could add userid,datetime here,filename,etc...  
              jsonFromExcel
            })

          }
          if (rABS) reader.readAsBinaryString(file);
          else reader.readAsArrayBuffer(file);
     })
  }

当然要在顶部导入:

import XLSX from 'xlsx' 

稍后,我将不得不添加逻辑以查看如果他们删除Excel文件以外的内容会发生什么情况。