I am working in a electron desktop app, and what I need to do is:
- Open a directory using ‘dialog.showOpenDialog’.
- Filter the files by their extension.
- Read filtered files (they have no header).
- Parse them into columns and return only columns 4 and 6 (coordinates).
- Return an array of arrays of all the files (Output example at the end).
With my little knowledge in js, this is my code so far, I’m stuck at point 4:
document.getElementById('btn-readfile').addEventListener('click', () => { dialog.showOpenDialog({ properties: ['openDirectory'] }).then(function(response) { if (!response.canceled) { dirname = response.filePaths[0] + '\' var fs = require('fs'); var path = require('path'); function readFiles(dirname, onFileContent, onError) { fs.readdir(dirname, function(err, files) { if (err) { onError(err); return; } filesList = files.filter(function(e) { return path.extname(e).toLowerCase() === '.txt' // ==> Filter files by extension }); filesList.forEach(function(filesList) { fs.readFile(dirname + filesList, 'utf-8', function(err, content) { if (err) { onError(err); return; } onFileContent(filesList, content); }); }); }); } var data = {}; readFiles(dirname, function(filesList, content) { data[filesList] = content; console.log(data[filesList]); }, function(err) { throw err; }); } else { console.log("no file selected"); } }); }, false);
Raw file:
-1 2021-01-20 08:11:19 43.30981408167 N 13.73270596167 E 1.08 M 4 -1 2021-01-20 08:11:20 43.30981406000 N 13.73270596333 E 1.07 M 4 -1 2021-01-20 08:11:21 43.30981403667 N 13.73270598333 E 1.07 M 4 -1 2021-01-20 08:11:22 43.30981403833 N 13.73270598500 E 1.07 M 4 1 2021-01-20 08:11:23 43.30981406333 N 13.73270597333 E 1.07 M 4 2 2021-01-20 08:11:24 43.30981404833 N 13.73270598167 E 1.07 M 4 3 2021-01-20 08:11:25 43.30981459167 N 13.73270569667 E 1.08 M 4 9 2021-01-20 08:11:26 43.30981820000 N 13.73270345667 E 1.07 M 4
Desired Output: an array of arrays, where every array represent columns 4 and 6 from every file in the folder.
var latlng = [ [ [ 45.64172279, 10.19579398], [ 45.64193714, 10.1958776], [ 45.64220345, 10.19598908], [ 45.6423983, 10.19606341], [ 45.6429504, 10.19632354], [ 45.64329464, 10.19658367], [ 45.64341805, 10.19758703] ], [ [ 45.64339856, 10.19838601], [ 45.64313876, 10.1987855], [ 45.64244377, 10.19869259], [ 45.6418527, 10.19879479], [ 45.6415669, 10.19715967], [ 45.64170331, 10.19648147], [ 45.64189167, 10.19615631] ] ];
Advertisement
Answer
Don’t cram everything into the event handler, that’s not reusable and has horrible maintainability. Make functions that take over the fundamental parts of your task.
First, top-level dependencies go to the top.
const fs = require('fs'); const path = require('path');
A function that reads a directory and returns a promise for an array of filenames:
function getFilesAsync(dirname) { return new Promise((resolve, reject) => { fs.readdir(dirname, function(err, files) { if (err) reject(err); else resolve(files); }); }); }
A function that takes a filename and an optional encoding, and returns a promise for the file content:
function getFileContentAsync(filename, encoding) { return new Promise((resolve, reject) => { fs.readFile(filename, {encoding: encoding}, function (err, content) { if (err) reject (err); else resolve(content); }); }); }
A function that takes a block of text and splits it into rows and columns at certain positions (since your data uses fixed-width columns):
function splitFixedColumnData(text, positions) { return text.split('n').map(line => positions.concat(line.length).map( (pos, i) => line.substring(positions[i-1] || 0, pos).trim() // from the previous to the current column pos ) ); }
And a function that picks out certain elements from an array, so you can pick the columns you want to work with from the larger set of columns the previous function returns:
function pluckArray(arr, indexes) { return arr.reduce((result, v, i) => { if (indexes.includes(i)) result.push(v); return result; }, []); }
And with all these defined, we can combine them to do something useful:
document.getElementById('btn-readfile').addEventListener('click', async () => { let dlg = await dialog.showOpenDialog({ properties: ['openDirectory'] }); if (dlg.canceled) { console.log("no file selected"); return; } try { let txtFiles = (await getFilesAsync(root)) .filter(fn => path.extname(fn).toLowerCase() === '.txx') .map(fn => path.join(root, fn)); let pendingContents = txtFiles.map(fn => getFileContentAsync(fn, 'utf-8')); let contents = await Promise.all(pendingContents); let columnData = contents.map(text => splitFixedColumnData(text, [4, 16, 28, 44, 48, 64, 68, 76, 80])); let latlng = columnData.map(rows => rows.map(row => pluckArray(row, [3, 5]))); for (let i = 0; i < txtFiles.length; i++) { console.log(txtFiles[i], latlng[i]); } } catch (err) { console.log(err); } }, false);