Reading files with JavaScript

3

I want my code to use the data provided by a file that is in the same root, I know it is done with the FileReader () constructor but I am learning to program and I do not understand how it should work.

Example: add two numbers provided by the file numeros.txt

The numbers file contains the following:

3 7 

The code to solve this would be:

function sum(a, b) {
  return a+b;
}

Sorry for the newbie.

    
asked by Jóse M Montaño 31.08.2018 в 23:48
source

2 answers

4

Considering that the question can be in the browser as in node.js , the answers would be:

In the browser

The browser does not have access to your local files unless you explicitly use an input of type file and choose a file. (Otherwise the browser could read all your local disk and that would be a giant security hole)

 <input type="file" id="archivo">

Data that input in the DOM, you add a listener to your element of type input type=file .

document.getElementById("archivo").addEventListener("change", (event) => {

});

Within that function, instances a FileReader

var fileReader = new FileReader();

To that fileReader you put a listener that executes when the file has loaded. The content of the file will be in the property result

fileReader.onload = function (e) {
    var contents = fileReader.result;
};

Then you pass the file that was selected in the input and tell it to read it as text:

fileReader.readAsText(files[0]);

Note that files can be several files if the input is multiple, so even if you accept a single file, files is an array and in this case we want the only file, files[0] .

When you finish reading it, it will invoke the function above.

If you are certain that the file is a text that has numbers separated by spaces, I leave a practical example that would allow (if you wanted) add more than two numbers, changing the footprint of the function (but it is a detail that in this case is irrelevant)

function sum(a, b) {
  return a + b;
}
document.getElementById("archivo").addEventListener("change", (event) => {
  var files = document.getElementById("archivo").files;
  var fileReader = new FileReader();
  fileReader.onload = function(e) {
    var contents = fileReader.result,
      argumentos = contents.split(/\s+/);
    argumentos_numericos = argumentos.map((argumento) => {
      return 1 * argumento
    });
    console.log(sum.apply(sum, argumentos_numericos));



  };
  fileReader.readAsText(files[0]);

}, false);
<input type="file" id="archivo">

Note: I am not doing any validation and converting the text arguments to number to make the addition I am doing it crudely, multiplying the string by 1.

In node.js

You use the fs module built into node.

fs = require('fs');

In node you have access to all the files on the disk for what you can do:

let data = fs.readFileSync('numeros.txt');
//    ... hacer algo con data...

Or

fs.readFile('numeros.txt', (err, data) => {
    if(err) {
       console.error(err);
       return;
    }
    ... hacer algo con data ...
});

The difference between using readFileSync vs readFile is that the first blocks the event-loop while the second one allows you to continue doing other things while reading the file. In this example, it's irrelevant.

But here it is important to note that when using any of these two methods, what you get in data is a Buffer And that Buffer you must convert it to string to use it as you want.

try {
   let data = fs.readFileSync('numeros.txt'),
   contenido = data.toString('UTF8');
} catch (err) {
   console.error(err);
}

Why do I wrap everything in a try/catch block? Well, it's equivalent to the way you detect the error in the asynchronous version. If the file does not exist it gets an error of type ENOENT or if it does not have read permissions an error of type EACCES .

Now contenido contains (valid bray) string 1 2 .

That content is converted into an array of integers using

enterosArray = contenido.split(" ").map(num=> parseInt(num, 10))

If you notice, parseInt expects two arguments. The string that you must cast to integer and the radix-parameter. By default it is assumed that you want to convert to integer with base 10, but if your file contains:

01 11
  • parseInt(num,10) would be 1 and 11
  • parseInt(num,2) would be 1 and 3
  • parseInt(num,16) would be 1 and 17.

If you omit the radix-parameter, a linter would plead you by using parseInt(num) saying:

missing-radix-parameter

Then you have the function that makes the addition. In your question the function was:

function sum(a, b) {
  return a+b;
}

That expects two addends and returns its sum. If you want to accept an array and return your sum, you can do as you pose in your answer:

function sum(data) {
  data.map((num) => solved+=num)
  console.log(solved);
}

With two caveats:

  • solved is not defined, you should initialize it before putting

    let solved = 0;

  • An arrow function should not return an assignment (a linter will tell you no-return-assign so within map you should use

    let solved = 0;
     data.map ((num) = > {     let partial_product = solved + = num;  });  console.log (solved);

  • But you are declaring resultado_parcial without major relevance. It would be smarter to omit the declaration of solved and use Array.reduce

    let solved = data.reduce((accum, num) => {
        accum += num;
        return accum;
    }, 0);
    
    console.log(solved);
    

    Another possible solution would be to use spread operator defining the function as:

    function sum(...data) {
        let solved = data.reduce((accum, num) => { 
            accum += num;
            return accum;
        }, 0);
    
        console.log(solved);
    }
    

    With which you would be free to call it either as

    let resultado = sum(1,2,3,4,5);
    

    or as

    let resultado = sum.apply(sum, [1,2,3,4,5]);
    

    But the latter is just a detail that is at your discretion.

    Input validation:

    Suppose you do not know the content of numeros.txt , but you know that from it you must obtain an array of numbers. If the content were

     '1 2 3 4'
    

    There would be no problem in using .split(' ')

    But what would happen if the content were: 1|2,3 aaa 4_5-6.7 ?

    In that case you could ask to separate the string accepting as a separator anything other than a number by passing a regular expression to split :

       var enterosArray = '1|2,3 aaa 4_5-6.7'.split(/[^\d]+/).map(num => parseInt(num,10))
       console.log(enterosArray);
        
    answered by 01.09.2018 / 01:21
    source
    0

    The previous answer is perfect for frontend, in backend it would be something like this:

    const fileReader = require('fs');
    
    
    function sum(data) {
      data.map((num) => solved+=num)
      console.log(solved);
    }
    
    function fileLoad() {
      return fileReader.readFile('numeros.txt', 'utf8', function(err, data) {
          err ? err : sum(data.split(" ").map((num) => parseInt(num) ));
      });
    } 
    
    fileLoad();
    

    this runs in node.js, what you are doing is importing the module fs with the reserved word require ().

    const fileReader = require('fs');
    

    After this we can read the file with the variable fileReader, since it is the one that contains the whole module. the fs module (File System, this is your documentation link ) has a function call readFile that receives several parameters, the first is the path of the file, the third is a callback that has two parameters "err" and "data", in case there is an error, the error type returns (postscript, " ? "is equal to" if "but in this case is in a single line) otherwise sends the data to a function called" sum ".

    sum(data.split(" ").map((num) => parseInt(num)
    

    This part of the code could be a bit confusing for those of us who are just learning to program, here I am sending the parameters to "sum", but in the form of an array and turn them into integers. If you do not understand what happens, look for the methods split () and map ().

    function sum(data) {
     data.map((num) => solved+=num)
     console.log(solved);
    }
    

    Here happens the magic of the sum, and that's it. Greetings

        
    answered by 01.09.2018 в 23:41