0

Here is my problem:

I am trying to parse a local CSV file in JavaScript. The file looks like this:

Year,Promo,Surname,Name,Mail
2005/2006,0,XXXX,XXXXX,xxxxx.xxxxx@gmail.com
(...)
2006/2007,1,XXXX,XXXXX,xxxxx.xxxxx@gmail.com
(...)
2007/2008,2,XXXX,XXXXX,xxxxx.xxxxx@gmail.com
etc.

I tried to parse it using several librairies (PapaParse.js, jquery-csv, d3.js...), but:

  • either the parsing fails (my array is empty)

  • or I get a XMLHttpRequest cannot load - Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource error, since my file is stored locally.

Is there a simple solution to parse a CSV file in JavaScript, in order to access the data? I looked up hundreds of posts on forums but I could not get it to work.

Thank you very much (excuse me, I am quite new in JS).

Tom.

Tom Février
  • 45
  • 1
  • 8
  • I think you have more than one problem at once. Where do you get your file from? Perhaps you should start using a local file, then move further. – Marcel Apr 05 '17 at 12:41
  • Are you using a server? – Gerardo Furtado Apr 05 '17 at 12:43
  • @Marcel it's a local file, OP said *"I am trying to parse a local CSV file"*. – Gerardo Furtado Apr 05 '17 at 12:43
  • In node I take it? See http://stackoverflow.com/questions/34980588/is-this-the-correct-way-to-wrap-readfilesync-in-a-promise – roberto tomás Apr 05 '17 at 12:49
  • @GerardoFurtado No I am not, at least for the moment – Tom Février Apr 05 '17 at 13:19
  • @robertotomás No I am not using Node... This is really a simple application. – Tom Février Apr 05 '17 at 13:21
  • @TomFévrier That's the problem. Any modern browser will deny access to local files. If you're using `d3.csv` to load and parse a local file, you have to use a server, like MAMP or WAMP. What is your OS? – Gerardo Furtado Apr 05 '17 at 13:22
  • @GerardoFurtado I'm on Ubuntu 16.04... Actually I've never set up a server, could you help me? – Tom Février Apr 05 '17 at 13:26
  • I'm not a Linux user. The best idea is posting a new question. – Gerardo Furtado Apr 05 '17 at 13:27
  • if it is with a browser, then you must let the user provide the file manually, like: http://stackoverflow.com/questions/27522979/read-a-local-text-file-using-javascript – roberto tomás Apr 05 '17 at 13:27
  • @GerardoFurtado But are you sure there is no way to simply parse a local file (without using d3.csv) in JS? – Tom Février Apr 05 '17 at 13:27
  • That has nothing to do with JS or D3. That's a security issue implemented by the browsers. – Gerardo Furtado Apr 05 '17 at 13:28
  • @robertotomás I don't want the user to provide the file, I just want to use data contained in a CSV file into my JavaScript program – Tom Février Apr 05 '17 at 13:28
  • @TomFévrier I think I see your problem now. You are already using XMLHTTPRequest to get a local file, but getting CORS issues. Not sure about a resolution, but at least I'm clear on the issue now :) – roberto tomás Apr 05 '17 at 13:28
  • @TomFévrier here are two options: make a micro server for your file and use that, or launch the browser with CORS disabled: https://www.thepolyglotdeveloper.com/2014/08/bypass-cors-errors-testing-apis-locally/ – roberto tomás Apr 05 '17 at 13:31
  • @robertotomás Thank you very much, it worked with a micro server! Well, since I have no choice but having a server, do you have any idea on how to set up a server on Ubuntu 16.04? – Tom Février Apr 05 '17 at 13:37

2 Answers2

0

this answer is canonical in that it addresses anyone's problem that might be described by the question. Only the first of these answers is meant for the OP, although, regarding the last comment, the edit section I added at the bottom is also specifically for the OP.

if you are doing this for a small, local app, you probably can do one of these two things:

  1. launch the browser with CORS disabled:

Chrome.exe --disable-web-security

in the source there is also instructions for firefox

src

  1. run a micro server for your files:

If you’ve got Python installed (most Mac and Linux users do), you can start a quick local web server for testing. Using the command prompt, navigate to the directory that has your HTML files and run the following command:

python -m SimpleHTTPServer

Your files should now be accessible from http://localhost:8000/ and may have a good chance of working when file:/// does not.

src

A better solution, if you run into CORS issues with the python server, might be local-web-server from node: https://www.npmjs.com/package/local-web-server

the typical user looking for an answer to this question is probably using node:

'use strict';

var fs = require('fs');

var readFilePromise = function(file) {
  return new Promise(function(ok, notOk) {
    fs.readFile(file, function(err, data) {
        if (err) {
          notOk(err)
        } else {
          ok(data)
        }
    })
  })
}

readFilePromise('/etc/passwd').then(function(data) {
  // do something with the data...
})

src

edit: setting it up for a simple application:

Make the server a serivce in rc.d or wherever. Follow a guide like this: https://blog.terminal.com/using-daemon-to-daemonize-your-programs/

Don't make the server a local service that is active! Instead, make a script to launch your app, and only from that script start the daemon. In your init script for the service, write a check to look for your app's PID or something every few minutes and autoshutdown when the app is no longer running.

Community
  • 1
  • 1
roberto tomás
  • 4,435
  • 5
  • 42
  • 71
0

Here is a code sample code for basic parsing of CSV you could try.

First step: Read the file.

We can read the file content using the FileReader class method readAsText, because the content in a CSV file is just some text . Read more about FileReader here: https://developer.mozilla.org/en-US/docs/Web/API/FileReader

This code should be in an 'async' function. Because we have used 'await' to wait for the promise to resolve or reject.

Here the file variable is the File Object you have from the file input HTML element.

   const fileContent = await(() => {
    const promise = new Promise((resolve,reject) => {
        const fileReader = new FileReader();
        fileReader.onloadend = ()=>{
            try {
                const content = fileReader.result;
                resolve(content);
            } catch (error) {
                reject(error);
            }
        };

        fileReader.readAsText(file);
    });

    return promise;
   })();

Second step: Transforming the file.

Here I transformed the file content into an array. A 2D array containing the CSV data.

/** extract the lines by splitting the text content by CRLF */
const linesArray = fileContent.split('\r\n');
const outcomeArray = [];

for (let rowIndex = 0; rowIndex < linesArray.length; rowIndex++) {

  /** Checking whether the line is empty or not. 
      It's possible that there is a blank line in the CSV file. 
      We shall process only if not blank */
  if (linesArray[rowIndex].trim()) {
    
    /** Extract the cell out of the current line */
    const currentline = linesArray[rowIndex].split(',').map((cellData, columnIndex) => {

      /** Forming the data as an object. This can be customised as needed */
      return {
        rowIndex,
        columnIndex,
        value: cellData?.trim()
      };
    });
    outcomeArray.push(currentline);
  }
}

Example If we parse a CSV having this content:

10,11
20,21

Output is a 2D array as below:

[
    [
        {
            "rowIndex": 0,
            "columnIndex": 0,
            "value": "10"
        },
        {
            "rowIndex": 0,
            "columnIndex": 1,
            "value": "11"
        }
    ],
    [
        {
            "rowIndex": 1,
            "columnIndex": 0,
            "value": "20"
        },
        {
            "rowIndex": 1,
            "columnIndex": 1,
            "value": "21"
        }
    ],
]
Bishnu Das
  • 462
  • 1
  • 3
  • 9