I am trying to filter files through node ncp library but it its filter is not working.
Once the filter gets false return it breaks the whole copying process
ncp(source, destination, options, function (err) {
if (err) {
console.error("backup error:", err);
}
console.log("Backup of done!');
});
var options = {
filter: function (file) {
console.log("copying file:", file);
var res = file.toString().indexOf("\\testdrive") !== -1;
console.log("res:", res);
return !res;
},
//filter: new RegExp("\\testdrive"),//Or RegEx intance
};
So once the filter function or RegEx instance gets false result the whole copy break
options.filter - a RegExp instance, against which each file name is tested to determine whether to copy it or not, or a function taking single parameter: copied file name, returning true or false, determining whether to copy file or not.
Just found the solution:
Seems like the filter RegExp/function will not only be called for the filenames that ncp is supposed to copy, but also for the foldernames.
The first foldername it filters is apparently the one you passed to ncp as source. And if that fails, ncp just stops copying anything in that folder.
See: https://github.com/AvianFlu/ncp/issues/130
For those coming late to the party (like me):
ncp traverse dir tree in a way that directory full paths are subjected to filter as well, on top of that, source directory itself is tested as well. In my case I wanted to copy bunch (lets call them one.svg, zwei.svg, tres.svg) of SVG files from single level directory called images, which resulted in following code:
ncp(srcImages, outImages, { filter: /.*(images|one\.svg|zwei\.svg|tres\.svg)$/ }, err => {
if (err) return console.error(err);
console.log('done!')
});
PS: please note that there is $ on the end of the regex meaning that we try to match end of the string
Related
The issue
I'm using the answer here Get all files recursively in directories NodejS
however, when I assign it to a constant I'm trying to return the directories so I can have them available in an array, I have looked through globs documentation for an asnwer https://github.com/isaacs/node-glob, however I have had no successful results, I have tried using glob.end() and I have also console.log the folds variable below, I can see all the list of available methods and I have tried to use some of them with no success, does anyone know how to return the array like in the code example below? Thank you!
const glob = require('glob');
const src = 'assets';
function getFiles(err, res){
if (err) {
console.log('Error', err);
} else {
return res
}
}
let folds = glob(src + '/**/*', getFiles);
I had the same problem.
glob() is asynchronous and that can make returning the end result somewhat complicated.
Use glob.sync() instead (where .sync stands for synchronous)
Example:
const files = glob.sync(src + '/**/*');
I have no idea how to ask this but it seems to be a fairly simple thing.
In this gulp task every occurrence of "old" is replaced with "new" on a bunch of files.
gulp.task('prefix-replace', function () {
return gulp.src('svg/*')
.pipe(replace('old', 'new'))
.pipe(gulp.dest('dist/'));
});
How to get the name of the file (or index or any unique id), so replacements would have a unique prefix for each file?
I tried with uuid:
gulp.task('prefix-replace', function () {
return gulp.src('svg/*')
.pipe(replace('old', uuidv4() + 'new'))
.pipe(gulp.dest('dist/'));
});
But this generates the SAME id for every replacement in all files (I know that's not a for loop but I'm struggling with streams at the moment as you can clearly see).
This will generate a new id for EVERY replacement, which is also not what I'm looking for:
gulp.task('prefix-replace', function () {
return gulp.src('svg/*')
.pipe(replace('term', function() {
return uuidv4() + 'term'
}))
.pipe(gulp.dest('dist/'));
});
How to get a unique id for each file?
gulp-replace with file object does have access to a vinyl file reference which you can use to get the current file name like so:
gulp.task('prefix-replace', function () {
return gulp.src('svg/*')
.pipe(replace('term', function() {
return this.file.relative + ': term'
}))
.pipe(gulp.dest('dist/'));
});
this.file.relative is a string so you can use string operations on it if need be (such as stripping off the extension). this.file.path gives you the full path to the current file.
The gulp-rename package has a prefix option https://www.npmjs.com/package/gulp-rename
I have been going through stackoverflow topics to find anything useful and there is really nothing. What i would need is (probably) some module, which you can call like this:
someModule('/start/path/', 'list', function(err, list) {
// list contains properly structured object of all subdirectories and files
});
also this
someModule('/start/path/', 'remove', function(err, doneFlag) {
// doneFlag contains something like true so i can run callback
});
I need above functionalities to create mini web-build ftp/code editor for my students.
It is important that listing includes correct structure of NOT only files but also subdirectories they are in. It doesnt really have to be that easy like in my desirable example, most important is that functionality is there. Thank you for all recomendations.
I made a module for my own needs which may help you. Look at alinex-fs. This is an extension of the node.js fs module and can be used as replacement.
Additionally it has a very powerful fs.find() method which will search recursively and match files like the linux find command. What to search for is done by an easy configuration hash.
Then you may loop over the result and remove everything (also recursive).
An example use may look like:
# include the module
var fs = require('alinex-fs');
# search asynchronouse
fs.find('/tmp/some/directory', {
include: 'test*',
type: 'dir'
modifiedBefore: 'yesterday 12:00'
# and much more possibilities...
}, function(err, list) {
if (err) return console.error(err);
# async included here for readability but mostly moved to top
var async = require('async');
# parallel loop over list
async.each(list, function(file, cb) {
# remove file or dir
return fs.remove(file, cb);
}, function(err) {
if (err) return console.log(err);
console.log('done');
});
});
if you already have the list of entries which you need to remove, you can also only use the inner function of the above code.
I hope that will help you to come a step further. If not please make your question more specific.
which is the most elegant way or technology to let a node.js server know if a file is created on a server?
The idea is: a new image has been created (from a webcam or so) -> dispatch an event!
UPDATE: The name of the new file in the directory is not known a priori and the file is generated by an external software.
You should take a look at fs.watch(). It allows you to "watch" a file or directory and receive events when things change.
Note: The documentation states that fs.watch is not consistent across platforms, so you should take that in to account before using it.
fs.watch(fileOrDirectoryPath, function(event, filename) {
// Something changed with filename, trigger event appropriately
});
Also something to be aware of from the docs:
Providing filename argument in the callback is not supported on every
platform (currently it's only supported on Linux and Windows). Even on
supported platforms filename is not always guaranteed to be provided.
Therefore, don't assume that filename argument is always provided in
the callback, and have some fallback logic if it is null.
If filename is not available on your platform and you're watching a directory you may need to do something where you initially read the directory and cache the list of files in it. Then, when you get an event from fs.watch, read the directory again and compare it to the cached list of files to see what was added (if anything).
Update 1: There's a good module called watch, on github, which makes it easy to watch a directory for new files.
Update 2: I threw together an example of how to use fs.watch to get notified when new files are added to a directory. I think the module I linked to above is probably the better way to go, but I thought it would be nice to have a basic example of how it might work if you were to do it yourself.
Note: This is a fairly simplistic example just to show how it could work in general. It could almost certainly be done more efficiently and it's far from throughly tested.
function watchForNewFiles(directory, callback) {
// Get a list of all the files in the directory
fs.readdir(directory, function(err, files) {
if (err) {
callback(err);
} else {
var originalFiles = files;
// Start watching the directory for new events
var watcher = fs.watch(directory, function(event, filename) {
// Get the updated list of all the files in the directory
fs.readdir(directory, function(err, files) {
if (err) {
callback(err);
} else {
// Filter out any files we already knew about
var newFiles = files.filter(function(f) {
return (originalFiles.indexOf(f) < 0);
});
// Reset our list of "original" files
originalFiles = files;
// If there are new files detected, call the callback
if (newFiles.length) {
callback(null, newFiles);
}
}
})
});
}
});
}
Then, to watch a directory you'd call it with:
watchForNewFiles(someDirectoryPath, function(err, files) {
if (err) {
// handle error
} else {
// handle any newly added files
// "files" is an array of filenames that have been added to the directory
}
});
I came up with my own solution using this code here:
var fs = require('fs');
var intID = setInterval(check,1000);
function check() {
fs.exists('file.txt', function check(exists) {
if (exists) {
console.log("Created!");
clearInterval(intID);
}
});
}
You could add a parameter to the check function with the name of the file and call it in the path.
I did some tests on fs.watch() and it does not work if the file is not created. fs.watch() has multiple issues anyways and I would never suggest using it... It does work to check if the file was deleted though...
We have a buffer we'd like to write to a file. If the file already exists, we need to increment an index on it, and try again. Is there a way to create a file only if it doesn't exist, or should I just stat files until I get an error to find one that doesn't exist already?
For example, I have files a_1.jpg and a_2.jpg. I'd like my method to try creating a_1.jpg and a_2.jpg, and fail, and finally successfully create a_3.jpg.
The ideal method would look something like this:
fs.writeFile(path, data, { overwrite: false }, function (err) {
if (err) throw err;
console.log('It\'s saved!');
});
or like this:
fs.createWriteStream(path, { overwrite: false });
Does anything like this exist in node's fs library?
EDIT: My question isn't if there's a separate function that checks for existence. It's this: is there a way to create a file if it doesn't exist, in a single file system call?
As your intuition correctly guessed, the naive solution with a pair of exists / writeFile calls is wrong. Asynchronous code runs in unpredictable ways. And in given case it is
Is there a file a.txt? — No.
(File a.txt gets created by another program)
Write to a.txt if it's possible. — Okay.
But yes, we can do that in a single call. We're working with file system so it's a good idea to read developer manual on fs. And hey, here's an interesting part.
'w' - Open file for writing. The file is created (if it does not
exist) or truncated (if it exists).
'wx' - Like 'w' but fails if path exists.
So all we have to do is just add wx to the fs.open call. But hey, we don't like fopen-like IO. Let's read on fs.writeFile a bit more.
fs.readFile(filename[, options], callback)#
filename String
options Object
encoding String | Null default = null
flag String default = 'r'
callback Function
That options.flag looks promising. So we try
fs.writeFile(path, data, { flag: 'wx' }, function (err) {
if (err) throw err;
console.log("It's saved!");
});
And it works perfectly for a single write. I guess this code will fail in some more bizarre ways yet if you try to solve your task with it. You have an atomary "check for a_#.jpg existence, and write there if it's empty" operation, but all the other fs state is not locked, and a_1.jpg file may spontaneously disappear while you're already checking a_5.jpg. Most* file systems are no ACID databases, and the fact that you're able to do at least some atomic operations is miraculous. It's very likely that wx code won't work on some platform. So for the sake of your sanity, use database, finally.
Some more info for the suffering
Imagine we're writing something like memoize-fs that caches results of function calls to the file system to save us some network/cpu time. Could we open the file for reading if it exists, and for writing if it doesn't, all in the single call? Let's take a funny look on those flags. After a while of mental exercises we can see that a+ does what we want: if the file doesn't exist, it creates one and opens it both for reading and writing, and if the file exists it does so without clearing the file (as w+ would). But now we cannot use it neither in (smth)File, nor in create(Smth)Stream functions. And that seems like a missing feature.
So feel free to file it as a feature request (or even a bug) to Node.js github, as lack of atomic asynchronous file system API is a drawback of Node. Though don't expect changes any time soon.
Edit. I would like to link to articles by Linus and by Dan Luu on why exactly you don't want to do anything smart with your fs calls, because the claim was left mostly not based on anything.
What about using the a option?
According to the docs:
'a+' - Open file for reading and appending. The file is created if it does not exist.
It seems to work perfectly with createWriteStream
This method is no longer recommended. fs.exists is deprecated. See comments.
Here are some options:
1) Have 2 "fs" calls. The first one is the "fs.exists" call, and the second is "fs.write / read, etc"
//checks if the file exists.
//If it does, it just calls back.
//If it doesn't, then the file is created.
function checkForFile(fileName,callback)
{
fs.exists(fileName, function (exists) {
if(exists)
{
callback();
}else
{
fs.writeFile(fileName, {flag: 'wx'}, function (err, data)
{
callback();
})
}
});
}
function writeToFile()
{
checkForFile("file.dat",function()
{
//It is now safe to write/read to file.dat
fs.readFile("file.dat", function (err,data)
{
//do stuff
});
});
}
2) Or Create an empty file first:
--- Sync:
//If you want to force the file to be empty then you want to use the 'w' flag:
var fd = fs.openSync(filepath, 'w');
//That will truncate the file if it exists and create it if it doesn't.
//Wrap it in an fs.closeSync call if you don't need the file descriptor it returns.
fs.closeSync(fs.openSync(filepath, 'w'));
--- ASync:
var fs = require("fs");
fs.open(path, "wx", function (err, fd) {
// handle error
fs.close(fd, function (err) {
// handle error
});
});
3) Or use "touch": https://github.com/isaacs/node-touch
Todo this in a single system call you can use the fs-extra npm module.
After this the file will have been created as well as the directory it is to be placed in.
const fs = require('fs-extra');
const file = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureFile(file, err => {
console.log(err) // => null
});
Another way is to use ensureFileSync which will do the same thing but synchronous.
const fs = require('fs-extra');
const file = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureFileSync(file)
With async / await and Typescript I would do:
import * as fs from 'fs'
async function upsertFile(name: string) {
try {
// try to read file
await fs.promises.readFile(name)
} catch (error) {
// create empty file, because it wasn't found
await fs.promises.writeFile(name, '')
}
}
Here's a synchronous way of doing it:
try {
await fs.truncateSync(filepath, 0);
} catch (err) {
await fs.writeFileSync(filepath, "", { flag: "wx" });
}
If the file exists it will get truncated, otherwise it gets created if an error is raised.
This works for me.
// Use the file system fs promises
const {access} = require('fs/promises');
// File Exist returns true
// dont use exists which is no more!
const fexists =async (path)=> {
try {
await access(path);
return true;
} catch {
return false;
}
}
// Wrapper for your main program
async function mainapp(){
if( await fexists("./users.json")){
console.log("File is here");
} else {
console.log("File not here -so make one");
}
}
// run your program
mainapp();
Just keep eye on your async - awaits so everthing plays nice.
hope this helps.
You can do something like this:
function writeFile(i){
var i = i || 0;
var fileName = 'a_' + i + '.jpg';
fs.exists(fileName, function (exists) {
if(exists){
writeFile(++i);
} else {
fs.writeFile(fileName);
}
});
}