Reputation: 9240
I am trying to find the most recently created file in a directory using Node.js and cannot seem to find a solution. The following code seemed to be doing the trick on one machine but on another it was just pulling a random file from the directory - as I figured it might. Basically, I need to find the newest file and ONLY that file.
var fs = require('fs'); //File System
var audioFilePath = 'C:/scanner/audio/'; //Location of recorded audio files
var audioFile = fs.readdirSync(audioFilePath)
.slice(-1)[0]
.replace('.wav', '.mp3');
Many thanks!
Upvotes: 32
Views: 39670
Reputation: 55012
Another approach:
const fs = require('fs')
const glob = require('glob')
const newestFile = glob.sync('input/*xlsx')
.map(name => ({name, ctime: fs.statSync(name).ctime}))
.sort((a, b) => b.ctime - a.ctime)[0].name
Upvotes: 10
Reputation: 100506
This is a commonplace need - write files out to a temp dir and automatically open the most recent one.
The following works with node version 16:
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const fsPromises = fs.promises;
process.on('exit', code => {
console.log('exiting with code:', code);
});
const folder = path.join(process.env.HOME, 'publications/temp');
const c = cp.spawn('sh');
const files = fs.readdirSync(folder).map(v => path.resolve(folder + '/' + v));
const openFile = (file) => {
c.stdin.end(`(open "${file}" &> /dev/null) &> /dev/null &`);
};
if(files.length > 500) {
console.error('too many files, clean this folder up lol');
process.exit(1);
}
const newest = {file: null, mtime: null};
Promise.all(files.map(f => {
return fsPromises.stat(f).then(stats => {
if (!newest.file || (stats.mtime.getTime() > newest.mtime.getTime())) {
newest.file= f;
newest.mtime= stats.mtime;
}
});
})).then(v => {
if(!newest.file){
console.error('could not find the newest file?!');
return;
}
openFile(newest.file);
});
you may want to check for folders instead of files, and you could add something like this towards the beginning:
if (files.length === 1) {
if (fs.statSync(files[0]).isFile()) {
openFile(files[0]);
process.exit(0);
} else {
console.error('folder or symlink where file should be?');
process.exit(1);
}
}
Upvotes: 0
Reputation: 13023
An async version of @pguardiario's functional answer (I did this myself then found theirs halfway down the page when I went to add this).
import {promisify} from 'util';
import _glob from 'glob';
const glob = promisify(_glob);
const newestFile = (await Promise.all(
(await glob(YOUR_GLOB)).map(async (file) => (
{file, mtime:(await fs.stat(file)).mtime}
))
))
.sort(({mtime:a}, {mtime:b}) => ((a < b) ? 1 : -1))
[0]
.file
;
Upvotes: 0
Reputation: 135
First, you need to order files (newest at the begin)
Then, get the first element of an array for the most recent file.
I have modified code from @mikeysee to avoid the path exception so that I use the full path to fix them.
The snipped codes of 2 functions are shown below.
const fs = require('fs');
const path = require('path');
const getMostRecentFile = (dir) => {
const files = orderReccentFiles(dir);
return files.length ? files[0] : undefined;
};
const orderReccentFiles = (dir) => {
return fs.readdirSync(dir)
.filter(file => fs.lstatSync(path.join(dir, file)).isFile())
.map(file => ({ file, mtime: fs.lstatSync(path.join(dir, file)).mtime }))
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
};
const dirPath = '<PATH>';
getMostRecentFile(dirPath)
Upvotes: 5
Reputation: 1763
A more functional version might look like:
import { readdirSync, lstatSync } from "fs";
const orderReccentFiles = (dir: string) =>
readdirSync(dir)
.filter(f => lstatSync(f).isFile())
.map(file => ({ file, mtime: lstatSync(file).mtime }))
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
const getMostRecentFile = (dir: string) => {
const files = orderReccentFiles(dir);
return files.length ? files[0] : undefined;
};
Upvotes: 7
Reputation: 261
Surprisingly, there is no example in this questions that explicitly uses Array functions, functional programming.
Here is my take on getting the latest file of a directory in nodejs. By default, it will get the latest file by any extension. When passing the extension property, the function will return the latest file for that extension.
The advantage of this code is that its declarative and modular and easy to understand as oppose to using "logic branching/control flows", of course given you understand how these array functions work 😀
const fs = require('fs');
const path = require('path');
function getLatestFile({directory, extension}, callback){
fs.readdir(directory, (_ , dirlist)=>{
const latest = dirlist.map(_path => ({stat:fs.lstatSync(path.join(directory, _path)), dir:_path}))
.filter(_path => _path.stat.isFile())
.filter(_path => extension ? _path.dir.endsWith(`.${extension}`) : 1)
.sort((a, b) => b.stat.mtime - a.stat.mtime)
.map(_path => _path.dir);
callback(latest[0]);
});
}
getLatestFile({directory:process.cwd(), extension:'mp3'}, (filename=null)=>{
console.log(filename);
});
Upvotes: 2
Reputation: 13306
Using pure JavaScript and easy to understand structure :
function getLatestFile(dirpath) {
// Check if dirpath exist or not right here
let latest;
const files = fs.readdirSync(dirpath);
files.forEach(filename => {
// Get the stat
const stat = fs.lstatSync(path.join(dirpath, filename));
// Pass if it is a directory
if (stat.isDirectory())
return;
// latest default to first file
if (!latest) {
latest = {filename, mtime: stat.mtime};
return;
}
// update latest if mtime is greater than the current latest
if (stat.mtime > latest.mtime) {
latest.filename = filename;
latest.mtime = stat.mtime;
}
});
return latest.filename;
}
Upvotes: 2
Reputation: 4428
While not the most efficient approach, this should be conceptually straight forward:
var fs = require('fs'); //File System
var audioFilePath = 'C:/scanner/audio/'; //Location of recorded audio files
fs.readdir(audioFilePath, function(err, files) {
if (err) { throw err; }
var audioFile = getNewestFile(files, audioFilePath).replace('.wav', '.mp3');
//process audioFile here or pass it to a function...
console.log(audioFile);
});
function getNewestFile(files, path) {
var out = [];
files.forEach(function(file) {
var stats = fs.statSync(path + "/" +file);
if(stats.isFile()) {
out.push({"file":file, "mtime": stats.mtime.getTime()});
}
});
out.sort(function(a,b) {
return b.mtime - a.mtime;
})
return (out.length>0) ? out[0].file : "";
}
BTW, there is no obvious reason in the original post to use synchronous file listing.
Upvotes: 7
Reputation: 8520
[Extended umair's answer to correct a bug with current working directory]
function getNewestFile(dir, regexp) {
var fs = require("fs"),
path = require('path'),
newest = null,
files = fs.readdirSync(dir),
one_matched = 0,
i
for (i = 0; i < files.length; i++) {
if (regexp.test(files[i]) == false)
continue
else if (one_matched == 0) {
newest = files[i];
one_matched = 1;
continue
}
f1_time = fs.statSync(path.join(dir, files[i])).mtime.getTime()
f2_time = fs.statSync(path.join(dir, newest)).mtime.getTime()
if (f1_time > f2_time)
newest[i] = files[i]
}
if (newest != null)
return (path.join(dir, newest))
return null
}
Upvotes: 2
Reputation: 9
with synchronized version of read directory (fs.readdirSync) and file status (fs.statSync):
function getNewestFile(dir, regexp) {
newest = null
files = fs.readdirSync(dir)
one_matched = 0
for (i = 0; i < files.length; i++) {
if (regexp.test(files[i]) == false)
continue
else if (one_matched == 0) {
newest = files[i]
one_matched = 1
continue
}
f1_time = fs.statSync(files[i]).mtime.getTime()
f2_time = fs.statSync(newest).mtime.getTime()
if (f1_time > f2_time)
newest[i] = files[i]
}
if (newest != null)
return (dir + newest)
return null
}
you can call this function as follows:
var f = getNewestFile("./", new RegExp('.*\.mp3'))
Upvotes: 0
Reputation: 10498
Assuming availability of underscore
(http://underscorejs.org/) and taking synchronous approach (which doesn't utilize the node.js strengths, but is easier to grasp):
var fs = require('fs'),
path = require('path'),
_ = require('underscore');
// Return only base file name without dir
function getMostRecentFileName(dir) {
var files = fs.readdirSync(dir);
// use underscore for max()
return _.max(files, function (f) {
var fullpath = path.join(dir, f);
// ctime = creation time is used
// replace with mtime for modification time
return fs.statSync(fullpath).ctime;
});
}
Upvotes: 29
Reputation: 6591
this should do the trick ("dir" is the directory you use fs.readdir over to get the "files" array):
function getNewestFile(dir, files, callback) {
if (!callback) return;
if (!files || (files && files.length === 0)) {
callback();
}
if (files.length === 1) {
callback(files[0]);
}
var newest = { file: files[0] };
var checked = 0;
fs.stat(dir + newest.file, function(err, stats) {
newest.mtime = stats.mtime;
for (var i = 0; i < files.length; i++) {
var file = files[i];
(function(file) {
fs.stat(file, function(err, stats) {
++checked;
if (stats.mtime.getTime() > newest.mtime.getTime()) {
newest = { file : file, mtime : stats.mtime };
}
if (checked == files.length) {
callback(newest);
}
});
})(dir + file);
}
});
}
Upvotes: 3
Reputation: 8166
Unfortunately, I don't think the files are guaranteed to be in any particular order.
Instead, you'll need to call fs.stat (or fs.statSync) on each file to get the date it was last modified, then select the newest one once you have all of the dates.
Upvotes: 1