How to search for files by extension and containing string within folder and subfolders? - node.js

Is it possible to look for files of given extension by the containing string provided?
What should my approach be? For example the input is txt and hello, and the output will be list of all files containing the string hello with extension txt.

You would write this in your terminal: node main.js hello
For a given directory it will search inside all subdirectories and all files for a text file with hello
Here is the code:
const { readdirSync, readFileSync, lstatSync } = require('fs');
const path = require('path');
const getDir = source => {
const results = readdirSync(source);
results.forEach(function (result) {
if (lstatSync(path.join(source, result))
.isFile()) {
if (readFileSync(path.join(source, result))
.includes(argument) && path.extname(result)
.toLowerCase() === extension) {
console.log("Your string is is in file: ", result)
}
}
else if (lstatSync(path.join(source, result))
.isDirectory()) {
getDir(path.join(source, result));
}
});
}
const dir = process.cwd();
const extension = '.txt'; //You can change the extension type here
let argument = process.argv[2];
getDir(dir);

You can use FileSystem to get the contents of a folder with the readdir method, this returns you an array of strings.
Let's say your working directory is a src file, in which there is a files folder that you want to read. Your script would look something like this:
const fs = require('fs');
var files = fs.readdir('./files', (err, filenames) => {
if (err) throw err;
return filenames;
})
You can then separate your string using string methods. Let's say you want to have two variables, fileNameand fileExt
You would use the String.split(separator) method, and use the . character as separator.
var files = // fs snippet above
for (file in files) {
let fileComponents = file.split('.');
let fileName = fileComponents[0];
let fileExt = fileComponents[1];
// You can run your code on the name, and extension of your file here.
}
This will not work for files containing multiple dots in their name. You will need extra work on the array to make sure fileName contains every string concatenated, separated by a . up until the final index of your fileComponents string

Related

Bulk Renaming Files Based on JSON in Node Recurisvely

I'm wanting to bulk rename files within a folder based on a JSON file that I have with the following format:
{
"1": {
"Filename": "Background-1",
"New Filename": "Background-1#4"
},
"2": {
"Filename": "Background-2",
"New Filename": "Background-2#6"
},
The original Filenames are within a folder structure such as
Background
--Background-1
--Background-2
Other Folder
--Another-Filename
--Another-Filename-2
And so on and so forth. I want to copy the files with the new names, while retaining the name of the folder they're in, over to a new folder.
So far I've tried using fs and klaw-sync to read the filenames, traverse through directories, etc, but it seems wildly inefficient to run through each key and then run through each folder recurisvely to find a matching file, then rename it and copy. There's over 180 files and ~15 folders.
Any idea how I can approach this better, or any suggestions/examples I could use?
Here's what I've got so far.
Thanks.
// Require Node's File System module
const fs = require('fs');
var path = require('path');
var klawSync = require('klaw-sync');
// Read the JSON file
fs.readFile(__dirname + '/rename_config.json', function (error, data) {
if (error) {
console.log(error);
return;
}
const obj = JSON.parse(data);
// Iterate over the object
Object.keys(obj).forEach(key => {
// Create an empty variable to be accesible in the closure
var paths;
// The directory that you want to explore
var directoryToExplore = path.join(__dirname, '../art');
try {
paths = klawSync(directoryToExplore);
} catch (err) {
console.error(err);
}
//console.log(paths);
//traverse through paths to find an equal name
//find the path of that equivalent name, then rename to new directory
});
});

How can I use Node.js fs to sort a set of folders according to their created date?

I'm building a node.js application in which I need to read all the folders in a parent folder and display their names in the order they were created on the page. Here is what I have so far:
function getMixFolders() {
const { readdirSync } = require('fs');
const folderInfo = readdirSync('./shahspace.com/music mixes/')
.filter(item => item.isDirectory() && item.name !== 'views');
return folderInfo.map(folder => folder.name);
}
As you can see, I haven't implemented sorting. This is because readdirSync doesn't return the information I need. The only things it returns are the name of the folder and something called the Symbol(type) (which seems to indicate whether its a folder or file).
Is there another method for getting more details about the folders I'm reading from the parent folder? Specifically the created date?
There is no super efficient way in nodejs to get a directory listing and get statistics on each item (such as createDate). Instead, you have to distill the listing down to the files/folders you're interested in and then call fs.statSync() (or one of the similar variants) on each one to get that info. Here's a working version that looks like it does what you want:
Get directory list using the {withFileTypes: true} option
Filter to just folders
Ignore any folders named "views"
Get createDate of each folder
Sort the result by that createDate in ascending order (oldest folders first)
This code can be run as it's own program to test:
const fs = require('fs');
const path = require('path');
const mixPath = './shahspace.com/music mixes/';
function getMixFolders() {
const folderInfo = fs.readdirSync(mixPath, { withFileTypes: true })
.filter(item => item.isDirectory() && item.name !== 'views')
.map(folder => {
const fullFolderPath = path.join(path.resolve(mixPath), folder.name);
const stats = fs.statSync(fullFolderPath);
return { path: fullFolderPath, ctimeMs: stats.ctimeMs }
}).sort((a, b) => {
return a.ctimeMs - b.ctimeMs;
});
return folderInfo;
}
let result = getMixFolders();
console.log(result);
If you wanted the final array to be only the folder names without the createDates you could add one more .map() to transform the final result.

Adding files in directory to an array

I am really new to node.js. I need to read .json files from a directory and then add them to an array and return it. I am able to read each file separately by passing the address:
const fs = require("fs");
fs.readFile("./fashion/customer.json", "utf8", (err, jsonString) => {
if (err) {
console.log("Error reading file from disk:", err);
return;
}
try {
const customer = JSON.parse(jsonString);
console.log("Customer address is:", customer.address); // => "Customer address is: Infinity Loop Drive"
} catch (err) {
console.log("Error parsing JSON string:", err);
}
});
But the same fashion folder has multiple json files. I want to add these files to an array and then return it. I tried using readdirSync but that just returned the file names. Is it possible to add json files to an array and return it?
Basically I require an array of this format:
Array[{contents of json file1}, {contents of json file2}, .....]
Any help is appreciated!
Here is a simple solution to your question:
const fs = require("fs");
const jsonFolder = './fashion'
var customerDataArray = []
fs.readdirSync(jsonFolder).forEach(file => {
let fileData = JSON.parse(fs.readFileSync(jsonFolder+'/'+file))
customerDataArray.push(fileData)
});
console.log(customerDataArray)
readdirSync returns an array with all the file names or objects in the directory. You can use forEach to iterate through every item in the array, which will be the file names in this scenario. To read the contents of each file, use readFileSync and specify the path to the file as the name of the directory plus the name of the file. The data is returned as a buffer and needs to be parsed using JSON.parse(), and then it is pushed to the customerDataArray.
I hope this answers your question!

How to get a folder size in nodejs with excluding certain paths with glob pattern?

I want to calculate the total archive file size before archiving to show a progress bar.
I have some folder which are exluded from zipping with are defined with a glob pattern.
How can you get a folder size with a glob filter?
It appears you can't use regular expressions; you can use https://www.npmjs.com/package/glob and loop through the files that match your glob pattern, and get the size of each. Something roughly like (i haven't tested this code):
const fs = require('fs')
const glob = require('glob')
let totalSize = 0 // bytes
// options is optional
glob("**/*.js", options, function (er, files) {
files.forEach(f => {
totalSize += fs.statSync(f)
})
})
With the help of above answer this is the solution
const glob = require('glob');
const fs = require('fs');
function getFolderSizeByGlob(folder, { ignorePattern: array }) {
const filePaths = glob.sync('**', { // "**" means you search on the whole folder
cwd: folder, // folder path
ignore: array, // array of glob pattern strings
absolute: true, // you have to set glob to return absolute path not only file names
});
let totalSize = 0;
filePaths.forEach((file) => {
console.log('file', file);
const stat = fs.statSync(file);
totalSize += stat.size;
});
return totalSize;
}

Read files from inout dir, apply the regex, write all files to output dir all at once

I have two folders, input and output folder with many text files in the below format. How do I read all the files from the input folder,run the regex and write all the updated files to another output folder?I am using nodejs.
Input: $.Carpool[0].NoofSeats], [$.Carpool[1].NoofSeats]
So after replace with regex the updated text file should be:
Regex: str = str.replace(/\.[A-Z]/g, (m0) => m0.toLowerCase());
Output: [$.carpool[0].noOfSeats], [$.carpool[1].noOfSeats]
So far I got to reading files from the directory:
const fs= require("fs");
let directory = "Input" // Desktop/Input
let files = fs.readdirSync(directory)
console.log(files);
You want to loop through the files, assuming if the contents are a text file in UTF-8 format here is an example.
You use fs.readFile to read a specific file after listing directory.
Then use fs.writeFile to write a new file with contents.
I use /directory/${f} for the new file directory path and ${f} for filename that was opened.
const fs = require("fs");
// Directory
let directory = "/";
// Files
let files = fs.readdirSync(directory);
// Loop through the files
files.forEach(f => {
// Read the contents in UTF-8 format
fs.readFile(f, 'utf8', function(err, contents) {
if (err) { console.log(err); }
// Output Contents
console.log(contents);
// Perform regex here
contents = contents.replace(/\.[A-Z]/g, (m0) => m0.toLowerCase());
// Write new file to path /new, with contents
fs.writeFile(`/directory/${f}`, contents, function(err) {
if (err) {
// Error writing
return console.log(err);
}
console.log("The file was saved!");
});
});
});

Resources