在Typescript中将CSV转换为JSON

15

我正在尝试从使用文件上传器输入上传的CSV文件中接收的数据创建一个JSON文件。

我已经在JavaScript中找到了许多此类文章,但在TypeScript中它们对我来说并不完全有效。

当我运行下面的代码时,我收到的错误是 csv.Split 不是一个函数,有没有人有任何想法如何修改我的代码使其工作。

如果您需要更多信息,请告诉我。谢谢提前。

component.ts

public testFile() {
    var file = (<HTMLInputElement>document.getElementById('fileInput')).files[0];        

    var jsonFile = this.csvJSON(file);


    // Set Http POST options
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    // Call Api with test connection data 
    this.http
        .post('/api/TestConnection/TestConnection', jsonFile, options)
        .subscribe(data => {
            // alert request ok
            alert('ok');
        }, error => {
            // Log error
            console.log(error.json());
        });
}

public csvJSON(csv) {
    var lines = csv.split("\n");

    var result = [];

    var headers = lines[0].split(",");

    for (var i = 1; i < lines.length; i++) {

        var obj = {};
        var currentline = lines[i].split(",");

        for (var j = 0; j < headers.length; j++) {
            obj[headers[j]] = currentline[j];
        }

        result.push(obj);

    }

    //return result; //JavaScript object
    return JSON.stringify(result); //JSON
}

如果你将CSV数据转换为哈希表(数组),然后再将其转换为JSON,这样不是更容易阅读和理解吗? - IvRRimUm
肯定有更好的方法来做这件事,这正是我请求建议的原因。 - Toby Jackson
好的,你当前的代码有哪些错误? - IvRRimUm
csv.split并不存在。 - Toby Jackson
你应该使用 FileReader.readAsText 来读取文件,然后将其发送到 csvJSON 方法。 - Aleksey L.
4个回答

15

您正在将 File 对象传递给 csvJSON 方法,而不是文件的文本内容。您可以使用 FileReader 去读取文件的内容。以下是一个示例:

const convertFile = () => {
  const input = document.getElementById('fileInput');

  const reader = new FileReader();
  reader.onload = () => {
    let text = reader.result;
    console.log('CSV: ', text.substring(0, 100) + '...');
    
    //convert text to json here
    //var json = this.csvJSON(text);
  };
  reader.readAsText(input.files[0]);
};
<input type='file' onchange='convertFile(event)' id='fileInput'>


5

以下是我在CSV转JSON上的工作,完美运作。

Stackbliz演示

contact-imports.component.ts

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { ToastrService } from 'ngx-toastr';

@Component({
  selector: 'app-contact-imports',
  templateUrl: './contact-imports.component.html',
  styleUrls: ['./contact-imports.component.scss']
})


export class ContactImportsComponent implements OnInit {

  csvContent: string;
  contacts: Array<any> = [];
  properties:any = "";
  flag:boolean = false;
  constructor( private toastr: ToastrService) { }
  ngOnInit() {
    
  }

  
  onFileLoad(fileLoadedEvent) {
    const textFromFileLoaded = fileLoadedEvent.target.result;
    this.csvContent = textFromFileLoaded;

    //Flag is for extracting first line
    let flag = false;
    // Main Data
    let objarray: Array<any> = [];
    //Properties
    let prop: Array<any> = [];
    //Total Length
    let size: any = 0;

    for (const line of this.csvContent.split(/[\r\n]+/)) {

      if (flag) {

        let obj = {};
        for (let k = 0; k < size; k++) {
          //Dynamic Object Properties
          obj[prop[k]] = line.split(',')[k]
        }
        objarray.push(obj);

      } else {
        //First Line of CSV will be having Properties
        for (let k = 0; k < line.split(',').length; k++) {
          size = line.split(',').length;
          //Removing all the spaces to make them usefull, also removing any " characters 
          prop.push(line.split(',')[k].replace(/ /g, '').replace(/"/g, ""));
        }
        flag = true;
      }
    }
    this.contacts = objarray;
    this.properties = [];
  
    this.properties = prop;
    console.log(this.properties);
    console.log(this.contacts);
    this.flag = true;
  

    // console.log(this.csvContent);
  }




  onFileSelect(input: HTMLInputElement) {

    const files = input.files;
    var fileTypes = ['csv'];  //acceptable file types

    if (files && files.length) {
      var extension = input.files[0].name.split('.').pop().toLowerCase(),  //file extension from input file
      isSuccess = fileTypes.indexOf(extension) > -1;  //is extension in acceptable types
       //console.log(isSuccess);
      //  console.log("Filename: " + files[0].name);
      // console.log("Type: " + files[0].type);
      //  console.log("Size: " + files[0].size + " bytes");
      if(isSuccess){
        const fileToRead = files[0];

        const fileReader = new FileReader();
        fileReader.onload = this.onFileLoad;
  
  
        fileReader.readAsText(fileToRead, "UTF-8");
      }else{
        this.toastr.error("Invalid File Type", 'Failed');
      }

    
    }

  }
}

contact-imports.component.html

 <div class="container-fluid">
      <div class="col-md-6">
          <img src="https://img.icons8.com/color/48/000000/csv.png"/> 
          <span class="text-muted" style="font-size: 22px;">Import Contacts From CSV</span>
        
     
          <div class="form-group">
                 <input class="form-control" accept=".csv" id="csv" type="file" (change)="onFileSelect($event.target)" name="myfile">
            </div>
      </div> 
    

  </div>

这将无法处理包含逗号的值。您可能需要增强您的for循环以考虑这些情况。 - murphy1310
我使用了您的解决方案来转换使用此Chrome扩展程序抓取的Facebook好友列表,但我无法访问返回区域内JSON对象中的属性。经过一些研究,我发现JSON对象由于某种原因具有字符串化的属性。所以是jsonObj."prop1"而不是jsonObj.prop1。我不知道是什么原因导致这种情况,但在推送属性之前添加.replace(/"/g, "")可以解决问题。您可以通过下载...进行测试。 - Maurice
使用Chrome扩展程序来抓取Facebook的好友列表。当你使用console.log(Object.getOwnPropertyNames(that.convertedArray[0]));打印数组中其中一个JSON对象的属性时,你会看到['"prop1"', '"prop2'"]而非['prop1', 'prop2']。我已经修改了你的代码,增加了.replace(/"/g, "")prop.push(line.split(',')[k].replace(/ /g, '')。希望你不介意。 - Maurice
我刚刚发现问题也出现在属性上。由于某种原因,这两个属性和值都用双引号引用了两次。可以对值使用.replace(/"/g, "")来解决这个问题。在特定行的属性值可能未定义的情况下,您还应该首先进行空值检查。 - Maurice

2

HTML

<input type="file" accept=".csv (change)="csv2Array($event)">

Typescript

csv2Array(fileInput: any){
//read file from input
this.fileReaded = fileInput.target.files[0];

let reader: FileReader = new FileReader();
reader.readAsText(this.fileReaded);

 reader.onload = (e) => {
 let csv: string = reader.result;
 let allTextLines = csv.split(/\r|\n|\r/);
 let headers = allTextLines[0].split(',');
 let lines = [];

  for (let i = 0; i < allTextLines.length; i++) {
    // split content based on comma
    let data = allTextLines[i].split(',');
    if (data.length === headers.length) {
      let tarr = [];
      for (let j = 0; j < headers.length; j++) {
        tarr.push(data[j]);
      }

     // log each row to see output 
     console.log(tarr);
     lines.push(tarr);
  }
 }
 // all rows in the csv file 
 console.log(">>>>>>>>>>>>>>>>>", lines);
} 
}

这不是返回 JSON 对象,而是只返回了一个普通的数组。 - Rohit Borude

0
import * as XLSX from 'xlsx'


uploadCSVFile(event) {
  const target: DataTransfer = <DataTransfer>(event.target);
  if (target.files.length !== 1) {
    throw new Error('Cannot use multiple files');
    }

    const filereader: FileReader = new FileReader();
    const selectedfile =  event.target.files[0];
    filereader.readAsBinaryString(selectedfile);
    filereader.onload = (event:any)=>{
      let binarydata =  event.target.result;
      let workbook  = XLSX.read (binarydata,{type:'binary'})
      workbook.SheetNames.forEach(sheet=>{
        const data = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]);
        console.log(data);
      })
      
    }


}

执行 npm install xlsx;

在 HTML 中

<input type="file" class="upload" (change)="uploadCSVFile($event)">

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接