I open an dialog in electron to select an folder and I want to read out the file path.
But the result.filePaths gives me an filePath with \\ what is not workible for me, to read later the files in the folder. 😅
Result now:
"P:\\Social Media\\Soundboard\\Sounds"
Expected Result:
"P:/Social Media/Soundboard/Sounds"
Is it any way to convert it to "/"? 🤔
My code:
const dialog = require('electron').remote.dialog
dialog.showOpenDialog({
properties: ['openDirectory', 'multiSelections']
}).then(result => {
//Get Selected Folders
folderpath = result.filePaths
console.log(folderpath)
});
Windows uses \ to separate nested resources instead of /. But it supports both. If you still want to convert \\ to /. You can try the below method.
//Get Selected Folders
folderpath = result.filePaths.replaceAll('\\', '/');
console.log(folderpath);
Here's how I develop electron apps to work on both unix and windows without any issues.
Instead of using the path module function, I extended the functionality by using the module below and call that instead. This will sanitize all paths and convert them to correct unix paths like '/var/path/file' or 'C:/path/file'.
Windows can actually work with unix paths for creating/reading/updating/moving files and folders.
export default {
extname (file) {
return path.extname(file)
},
resolve () {
return this.sanitizePath(Array.from(arguments).join('/').replace('//', '/'))
},
normalize () {
const file = this.resolve(...arguments)
return this.sanitizePath(path.normalize(file))
},
basename (file, ext = '') {
return this.sanitizePath(path.basename(file, ext))
},
dirname (file) {
return this.sanitizePath(path.dirname(file))
},
relative (from, to) {
return this.sanitizePath(path.relative(path.resolve(from), path.resolve(to)))
},
sanitizePath (absPath) {
// fix windows separator
return absPath.replaceAll(path.sep, '/')
}
}
The only time I needed windows specific paths was with shell.moveItemToTrash(file) and for that I had to us this client side function
convertPathForWin (file, os = navigator.platform) {
return (os.toLowerCase() === 'win32') ? file.replaceAll('/', '\\') : file
}
Related
I'm getting a webpack error when trying to require an image file I know exists in my v-img component here:
imgSrcFancy (imgsize) {
try {
// if in production, unless no imgsize is specified, use .imgs instead of fullsize
// if (imgsize === '' || process.env.NODE_ENV === 'development') {
if (imgsize === '') { // temporarily force always use .imgs for testing only
console.log('fallback on full-rez load')
return require(`~/content${this.dirp}/${this.src}`)
} else { // production and imgsize not empty
const path = require('path')
const ext = path.extname(this.src)
const name = path.basename(this.src, ext)
const loadstring = `~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`
console.log('fancy load from ' + loadstring)
return require(`~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`)
}
} catch (error) {
console.log('error with finding image for: ' + this.src)
console.log(error)
return null
}
Background:
I have a blog that uses nuxt-content.
The project is organized so that images are grouped along with post .md files in a folder for each post inside /content/posts. My starting v-img component works fine, requiring these images no problem. (note this last link is to the master branch that is deployed, while the earlier is to a feature branch)
My deployed site is very slow to load, so I wrote a python program to generate smaller versions of the images, all stored in a .imgs folder within each slug folder as follows:
- content/
- posts/
- post-slug-one/
- index.md
- my_image1.jpg
...
- .imgs/
- my_image1_large.jpg
- my_image1_tn.jpg
...
The python program is invoked as part of my netlify build command, e.g. python3 ./gen_tn.py && nuxt build && nuxt generate. This works fine.
To avoid clogging up disk space locally, I'm using NODE_ENV to just use full sizes when in development; this works fine too, but I've temporarily disabled this to test.
I generated thumbnails locally for testing, but the problem comes when I hit the line:
return require(`~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`)
I get an exception:
Error: Cannot find module './content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg'
at webpackContextResolve (content.*$:752)
at webpackContext (content.*$:747)
at VueComponent.imgSrcFancy (VImg.vue:59)
at Proxy.render (VImg.vue?ad21:7)
at VueComponent.Vue._render (vue.runtime.esm.js:3548)
at VueComponent.updateComponent (vue.runtime.esm.js:4055)
at Watcher.get (vue.runtime.esm.js:4479)
at Watcher.run (vue.runtime.esm.js:4554)
at flushSchedulerQueue (vue.runtime.esm.js:4310)
at Array.<anonymous> (vue.runtime.esm.js:1980)
But this file exists:
MBPro:bst-blog$ ls content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg
content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg
I've tried even hard-coding the image size, but that doesn't work either:
return require(\`~/content${this.dirp}/.imgs/${name}_large${ext}`)
What am I doing wrong? How do I fix this? Any guidance appreciated!
Ok.
Turns out the problem was with the name I was using for the thumbnails - webpack did not like .imgs. Changing it to imgs (or gen_tn_imgs to make adding a specific rule to .gitignore easy, in my case).
My final block looks like this:
methods: {
imgSrcFancy (imgsize) {
try {
// if in production, unless no imgsize is specified, use .imgs instead of fullsize
if (imgsize === '' || imgsize === 'orig' || process.env.NODE_ENV === 'development') {
// if (imgsize === '') { // temporarily force always use .imgs for testing only
console.log('fallback on full-rez load')
return require(`~/content${this.dirp}/${this.src}`)
} else { // production and imgsize not empty
const path = require('path')
const ext = path.extname(this.src)
const name = path.basename(this.src, ext)
const loadstring = `~/content${this.dirp}/gen_tn_imgs/${name}_${imgsize}.png`
console.log('fancy load from ' + loadstring)
return require(`~/content${this.dirp}/gen_tn_imgs/${name}_${imgsize}.png`) // working
}
} catch (error) {
console.log('error with finding image for: ' + this.src)
console.log(error)
return null
}
}
}
and it's called like so:
<a :href="imgSrcFancy('orig')">
<img :src="imgSrcFancy('large')" :alt="alt">
</a>
I wanted to delete multiple files which are ending with .pdf under the current directory. Suppose I have 3 different pdf files, 1 image file, and one text file, so in these, I want to delete those 3 different pdf files only.
What I have tried.
1st method
fs.unlinkSync('./'+*+pdfname); -> I know this does not make sense
2nd method
try {
var files = (here the list of files should come. However i am failing to get those);
var path="./"
files.forEach(path => fs.existsSync(path) && fs.unlinkSync(path))
} catch (err) {
console.error("not exist")
}
Any different approaches would be appreciated.
Update for the solution:
I have got the solution for my requirement, I just wanted my function to delete all the pdf files and function to be synchronous. However 99% of the solution given by the below author -> https://stackoverflow.com/a/66558251/11781464
fs.readdir is asynchronous and just needs to make it synchronous fs.readdirSync.
below is the updated code and all the credit should go to the author https://stackoverflow.com/a/66558251/11781464.
Updated code
try {
const path = './'
// Read the directory given in `path`
fs.readdirSync(path).forEach((file) => {
// Check if the file is with a PDF extension, remove it
if (file.split('.').pop().toLowerCase() === 'pdf') {
console.log(`Deleting file: ${file}`);
fs.unlinkSync(path + file)
}
});
console.log("Deleted all the pdf files")
return true;
} catch (err) {
console.error("Error in deleting files",err);
}
You can read the directory using fs.readdir and then check for PDF files and delete them. Like this:
fs = require('fs');
try {
path = './'
// Read the directory given in `path`
const files = fs.readdir(path, (err, files) => {
if (err)
throw err;
files.forEach((file) => {
// Check if the file is with a PDF extension, remove it
if (file.split('.').pop().toLowerCase() == 'pdf') {
console.log(`Deleting file: ${file}`);
fs.unlinkSync(path + file)
}
});
});
} catch (err) {
console.error(err);
}
Preliminary Reading
The current working directory of the Node.js process - see update below answer
Path methods
resolve
extName
File System methods
fs.readdirSync
fs.unlinkSync
and classes
dirent
Example
"use strict";
const fs = require('fs');
const path = require('path');
const cwd = process.cwd();
fs.readdirSync( cwd, {withFileTypes: true})
.forEach( dirent => {
if(dirent.isFile()) {
const fileName = dirent.name;
if( path.extname(fileName).toLowerCase() === ".pdf") {
fs.unlinkSync( path.resolve( cwd, fileName));
}
}
});
Notes
untested code
If unlinkSync fails I would assume it returns -1 as per the unlink(2) man page linked in documentation. Personally I would test this using a filename that doesn't exist in cwd.
I believe the {withFileTypes: true} option for readdirSync returns dirent objects with a mime-type value that would allow you to check for files of type application/pdf regardless of extension (not attempted in the example).
Update: path(resolve) adds the current working directory at the beginning of the returned path, when necessary, by default. path.resolve(fileName) will work equally as well as path.resolve(cwd, fileName) in the example.
It seems you know how to delete (unlink) the files - you are asking how to get the file paths?
Try using glob:
const pdfFiles = require("glob").globSync("*.pdf");
Hi here i am attaching tested code for delete all ( only ) .pdf files and not other extension files like .txt , .docs etc from directory.
Note : You can delete any files or directory only from server side.
const fs = require('fs');
const path = require('path')
fs.readdir('../path to directory', (err, files) => {
const pdfFiles = files.filter(el => path.extname(el) === '.pdf')
pdfFiles.forEach(file => {
console.log("Removing File -> ",file);
var filename = "../path to directory/"+file;
fs.unlink(filename,function(err){
if(err) return console.log(err);
console.log('file deleted successfully');
});
});
});
This will gives you a following result in console log.
Removing File -> note.pdf
Removing File -> note2.pdf
file deleted successfully
file deleted successfully
Please feel free to comment any query if have..
I am using the below code to split up a user provided path, create all intermediate dirs in the path and attach a timestamp to the ending file name. I am splitting the path with / first and then using forEach over the resulting array. Is there any better way/direct lib function to do this in javascript / nodejs.
function test(usrPath) {
var locMatches = usrPath.split("/")
locMatches.forEach (function (item) {
location = pathUtils.join(location,item)
if (!fs.existsSync(location)) {
fs.mkdirSync(location)
}
})
return pathUtils.join (location,usrPath + (new Date).toISOString().replace(/(^\d\d\d\d)|-|:|(\..*)/g,"").replace("T","_")+".log")
}
Ok, so there are path utils that allow to make the implementation better across platform.
Also, it gives a better managed access for working with path elements like root, dir, filename and extension. pathUtils.sep allows working on the dir elements more cross platform.
var pathUtils = require('path')
function test(usrPath) {
var pathElements = pathUtils.parse(usrPath)
pathElements.dir.split(pathUtils.sep).forEach (function (item) {
location = pathUtils.join(location,item)
if (!fs.existsSync(location)) {
fs.mkdirSync(location)
}
})
return pathUtils.join (location,pathElements.name + (new Date).toISOString().replace(/(^\d\d\d\d)|-|:|(\..*)/g,"").replace("T","_")+pathElements.ext.replace(/^$/i,".log"))
}
This is not working very well:
gulp.task('dev', function () {
console.log('concatenating development libs...')
var log = function (file, cb) {
console.log(file.path);
cb(null, file);
};
var zocialCss = 'zocial-flat.css';
request('http://my.blob.core.windows.net/shared-styles-webfonts/zocial-flat.css')
.pipe(fs2.createWriteStream(zocialCss));
var cssFiles = [
'./' + zocialCss,
'../bower_components/**/bootstrap.css',
];
fs.src(cssFiles)
.pipe(map(log))
.pipe(concat('styles.css'))
.pipe(gulp.dest(stylesPath));
});
My guess is fs2.createWriteStream(zocialCss) keeps the file locked (or open for writing) and it never closes, so concat ignores it (or silently fails). I can see zocial-flat.css being generated as expected (I would, by the way, like to delete the file after concatenation).
I have seen alternatives to this approach (like gulp-remote-src) and am open to any such suggestions.
Under my assets/ folder, I have numerous subfolders, each containing an arbitrary number of images, like so:
assets/article1/
assets/article2/
I'm trying to write a gulp task to locate all .jpg images within and generate their thumbnail versions, to be saved in a thumbs/ subfolder within the folder where each file resides:
assets/article1/ # original jpg images
assets/article1/thumbs/ # thumbnail versions of above..
assets/article2/
assets/article2/thumbs/
I've been trying various approaches but no luck. The closest I've come is:
gulp.task('thumbs', function () {
return gulp.src( './assets/**/*.jpg' )
.pipe( imageResize( { width: 200 } ) )
.pipe( gulp.dest( function( file ) { return file.base + '/thumbs/'; } ) );
});
However, this creates a single thumbs\ folder at the root of assets\
assets/article1/
assets/article2/
assets/thumbs/article1/
assets/thumbs/article2/
Is there a good info on the paths and wildcards anywhere? Clearly I'm not handling it well..
You could use path.dirname for that: http://nodejs.org/api/path.html#path_path_dirname_p
// require core module
var path = require('path');
gulp.task('thumbs', function () {
return gulp.src( './assets/**/*.jpg' )
.pipe( imageResize( { width: 200 } ) )
.pipe( gulp.dest( function( file ) { return path.join(path.dirname(file.path), 'thumbs'); } ) );
});
Here's what worked for me given the following directory structure (I simplified a bit to focus on just getting the files in the right place)
assets/article1/1.jpg
assets/article2/2.jpg
with a desired outcome of
assets/article1/1.jpg
assets/article1/thumbs/1.jpg
assets/article2/2.jpg
assets/article2/thumbs/2.jpg
Here's what worked for me (modified from this recipe https://github.com/gulpjs/gulp/blob/master/docs/recipes/running-task-steps-per-folder.md)
var gulp = require('gulp'),
rename = require('gulp-rename'),
path = require('path'),
fs = require('fs');
var scriptsPath = 'assets'; // folder to process
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function(file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
gulp.task('thumbs', function() {
var folders = getFolders(scriptsPath);
return folders.map(function(folder) {
return gulp.src(path.join(scriptsPath, folder, '/**/*.jpg'))
.pipe(rename({dirname: folder + '/thumbs/'}))
.pipe(gulp.dest(scriptsPath));
});
});
I've found another approach that may be useful for anyone searching this post.
My original goal was very similar to your request, and this approach may be adjusted to almost any particular need.
function scss(cb) {
src('./*/scss/*.scss')
.pipe(sourcemaps.init())
.pipe(sass())
.pipe(rename({extname: '.min.css'}))
.pipe(tap(function(file) {
//Enrich the file with crucial information about it's original path, you can save anything you may need. In my case filename is quite enough. It's important to move this block before any sourcemap write if you've any.
file.name = path.basename(file.path);
}))
.pipe(sourcemaps.write('.'))
.pipe(flatten()) //Remove file relative paths.
.pipe(dest(
function( file ) {
//Reconstruct final path using insight we saved before, and using a clean base path provided by flatten.
return path.join(path.dirname(file.path), file.name.replace(/\.min\..+$/, ''), 'static');
}));
cb();
}