Copying a pdf using node's fs results in a different file - node.js

I have the following code, which I expect to copy a pdf but it doesn't copy it exactly and the file size is off between 286KB vs the original 202KB and the copy does not open in a pdf reader. I tried this on other languages and I get the same issue. I get a similar if not identical result from opening the original pdf as a text file on vs code, copying and pasting the contents into a new file. Thank you!
const fs = require('fs');
fs.readFile('./original.pdf', 'utf8', (err, data) => {
fs.writeFile('./copy.pdf', chunk, err => {
console.error(err);
});
});
EDIT: To clarify, I'm not looking for another approach/library/api, but rather an explanation of why my method does not work and a modification of either the code or the copying and pasting the contents approach. Thank you!

You can use copyFile method from fs/promises:
import { copyFile } from 'fs/promises';
await copyFile('./original.pdf', './copy.pdf');
You can read more about it here.

const fs = require('fs');
fs.readFile('./original.pdf', (err, data) => {
fs.writeFile('./copy.pdf', data, err => {
console.error(err);
});
});
simply delete the encoding from the readFile-function and use the variable 'data' from the callback in the writeFile-function

Related

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!

Bad file descriptor, read, while extracting zip file using node-stream-zip

I have a zip file that has a folder like
1234/pic1.png
1234/pic2.png
1234/data.xlsx
I am trying to extract the spreadsheet (failing that, all files) using node-stream-zip.
const StreamZip = require('node-stream-zip');
const zip = new StreamZip({
file: path.join(downloadsDir, fileToFind),
storeEntries: true
});
zip.on('ready', () => {
if(!fs.existsSync('extracted')) {
fs.mkdirSync('extracted');
}
zip.extract('1234/', './extracted', err => {
console.log(err);
});
zip.close();
});
This produces
EBADF: bad file descriptor, read
In the extracted folder is one of the png files. But when following the guide to extract just the xlsx file it appears that the xlsx file is the one causing this error.
zip.extract('1234/data.xlsx', './extracted.xlsx', err => {
console.log(err);
});
Is the problem with the xlsx file? I can open it manually. Is it permissions-related? Node? This particular package?
Your problem is related to zip.close(). You're closing it on the same tick as you're invoking zip.extract().

writeFile no such file or directory

I have a file(data.file an image), I would like to save this image. Now an image with the same name could exist before it. I would like to overwrite if so or create it if it does not exist since before. I read that the flag "w" should do this.
Code:
fs.writeFile('/avatar/myFile.png', data.file, {
flag: "w"
}, function(err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
Error:
[Error: ENOENT: no such file or directory, open '/avatar/myFile.png']
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/avatar/myFile.png'
This is probably because you are trying to write to root of file system instead of your app directory '/avatar/myFile.png' -> __dirname + '/avatar/myFile.png' should do the trick, also check if folder exists. node.js won't create parent folder for you.
Many of us are getting this error because parent path does not exist. E.g. you have /tmp directory available but there is no folder "foo" and you are writing to /tmp/foo/bar.txt.
To solve this, you can use mkdirp - adapted from How to write file if parent folder doesn't exist?
Option A) Using Callbacks
const mkdirp = require('mkdirp');
const fs = require('fs');
const getDirName = require('path').dirname;
function writeFile(path, contents, cb) {
mkdirp(getDirName(path), function (err) {
if (err) return cb(err);
fs.writeFile(path, contents, cb);
});
}
Option B) Using Async/Await
Or if you have an environment where you can use async/await:
const mkdirp = require('mkdirp');
const fs = require('fs');
const writeFile = async (path, content) => {
await mkdirp(path);
fs.writeFileSync(path, content);
}
I solved a similar problem where I was trying to create a file with a name that contained characters that are not allowed. Watch out for that as well because it gives the same error message.
I ran into this error when creating some nested folders asynchronously right before creating the files. The destination folders wouldn't always be created before promises to write the files started. I solved this by using mkdirSync instead of 'mkdir' in order to create the folders synchronously.
try {
fs.mkdirSync(DestinationFolder, { recursive: true } );
} catch (e) {
console.log('Cannot create folder ', e);
}
fs.writeFile(path.join(DestinationFolder, fileName), 'File Content Here', (err) => {
if (err) throw err;
});
Actually, the error message for the file names that are not allowed in Linux/ Unix system comes up with the same error which is extremely confusing. Please check the file name if it has any of the reserved characters. These are the reserved /, >, <, |, :, & characters for Linux / Unix system. For a good read follow this link.
It tells you that the avatar folder does not exist.
Before writing a file into this folder, you need to check that a directory called "avatar" exists and if it doesn't, create it:
if (!fs.existsSync('/avatar')) {
fs.mkdirSync('/avatar', { recursive: true});
}
you can use './' as a prefix for your path.
in your example, you will write:
fs.writeFile('./avatar/myFile.png', data.file, (err) => {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
I had this error because I tried to run:
fs.writeFile(file)
fs.unlink(file)
...lots of code... probably not async issue...
fs.writeFile(file)
in the same script. The exception occurred on the second writeFile call. Removing the first two calls solved the problem.
In my case, I use async fs.mkdir() and then, without waiting for this task to complete, I tried to create a file fs.writeFile()...
As SergeS mentioned, using / attempts to write in your system root folder, but instead of using __dirname, which points to the path of the file where writeFile is invoked, you can use process.cwd() to point to the project's directory. Example:
writeFile(`${process.cwd()}/pictures/myFile.png`, data, (err) => {...});
If you want to avoid string concatenations/interpolations, you may also use path.join(process.cwd(), 'pictures', 'myFile.png') (more details, including directory creation, in this digitalocean article).

How to ignore hidden files in fs.readdir result

In node application i need to get all the files in the directory except that hidden files.
I have tried fs.readdir but it displaying hidden files also.
Using the regex from this answer, this simple solution removes all hidden files from the result:
fs.readdir('/path/to/directory', (err, list) => {
list = list.filter(item => !(/(^|\/)\.[^\/\.]/g).test(item));
// Your code
});
You can use:
fs.readdir('/path/to/directory', function(err, list) {
list.forEach(function (filename) {
if(! /^\..*/.test(filename)) {
// display files
}
});
});
The promise way
const fs = require('fs').promises;
const readdir = path => {
return fs
.readdir(path)
.then(list => list.filter(item => !/(^|\/)\.[^/.]/g.test(item)));
};
I use junk package to ignore hidden files.
var fs = require('fs');
var junk = require('junk');
fs.readdir('path', function (err, files) {
console.log(files.filter(junk.not));
});
Using a regular expression like the solution provided may remove some filesystems but not all files. And using the "Junk" module is using regular expressions on some defined system filenames. So the solution is simply to write a personal script managing the different cases by adding cases as they are discovered.

NodeJS: Asynchronous file read problems

New to NodeJS.
Yes I know I could use a framework, but I want to get a good grok on it before delving into the myriad of fine fine tools that are out there.
my problem:
var img = fs.readFileSync(path);
the above works;
fs.readFile(path, function (err, data)
{
if (err) throw err;
console.log(data);
});
the above doesn't work;
the input path is : 'C:\NodeSite\chrome.jpg'
oh and working on Windows 7.
any help would be much appreciated.
Fixed
Late night/morning programming, introduces errors that are hard to spot. The path was being set from two different places, and so the source path were different in both cases. Thankyou for your help. I am a complete numpty. :)
If you are not setting an encoding when reading a file, you will get the binary content.
So for example, the following snippet will output the content of the test file using UTF-8 encoding. If you don't use an encoding, you will get an output like "" on your console (raw binary buffer).
var fs = require('fs');
var path = "C:\\tmp\\testfile.txt";
fs.readFile(path, 'utf8', function (err, data) {
if (err) throw err;
console.log(data);
});
Another issue (especially on windows-based OS's) can be the correct escaping of the target path. The above example shows how path's on Windows have to be escaped.
java guys will just use this javascript asynchronous command as if in pure java , troublefreely :
var fs = require('fs');
var Contenu = fs.readFileSync( fILE_FULL_Name , 'utf8');
console.log( Contenu );
That should take care of small & big files.

Resources