How to create a file object with a path in NodeJS? - javascript

I want to know if it is possible to create a file object (name, size, data, ...) in NodeJS with the path of existing file ? I know that it is possible in client side but I see nothing for NodeJS.
In others words, I want the same function works in NodeJS :
function srcToFile(src, fileName, mimeType){
return (fetch(src)
.then(function(res){return res.arrayBuffer();})
.then(function(buf){return new File([buf], fileName, {type:mimeType});})
);
}
srcToFile('/images/logo.png', 'logo.png', 'image/png')
.then(function(file){
console.log(file);
});
And ouput will be like :
File {name: "logo.png", lastModified: 1491465000541, lastModifiedDate: Thu Apr 06 2017 09:50:00 GMT+0200 (Paris, Madrid (heure d’été)), webkitRelativePath: "", size: 49029, type:"image/png"…}

For those that are looking for a solution to this problem, I created an npm package to make it easier to retrieve files using Node's file system and convert them to JS File objects:
https://www.npmjs.com/package/get-file-object-from-local-path
This solves the lack of interoperability between Node's fs file system (which the browser doesn't have access to), and the browser's File object type, which Node cannot create.
3 steps are required:
Get the file data in the Node instance and construct a LocalFileData object from it
Send the created LocalFileData object to the client
Convert the LocalFileData object to a File object in the browser.
// Within node.js
const fileData = new LocalFileData('path/to/file.txt')
// Within browser code
const file = constructFileFromLocalFileData(fileData)

So, I search with File Systems and others possibilities and nothing.
I decide to create my own File object with JSON.
var imagePath = path.join('/images/logo.png', 'logo.png');
if (fs.statSync(imagePath)) {
var bitmap = fs.readFileSync(imagePath);
var bufferImage = new Buffer(bitmap);
Magic = mmm.Magic;
var magic = new Magic(mmm.MAGIC_MIME_TYPE);
magic.detectFile(imagePath, function(err, result) {
if (err) throw err;
datas = [{"buffer": bufferImage, "mimetype": result, "originalname": path.basename(imagePath)}];
var JsonDatas= JSON.parse(JSON.stringify(datas));
log.notice(JsonDatas);
});
}
The output :
{
buffer:
{
type: 'Buffer',
data:
[
255,
216,
255
... 24908 more items,
[length]: 25008
]
},
mimetype: 'image/png',
originalname: 'logo.png'
}
I think is probably not the better solution, but it give me what I want. If you have a better solution, you are welcome.

You can use arrayBuffer (thats what i did to make a downloadable pdf) or createReadStream / createWriteStream under fs(FileSystem objects)

Related

How to get a file in pure binary

I have a file that I upload using antdUpload
The html renderer :
<Upload
beforeUpload={((file: RcFile, fileList: RcFile[]): boolean => {this.requestUpload(file, (fileList.length || 0 )); return false;})}
></Upload>
The code part :
requestUpload(file: RcFile, nbFile: number): void {
const r = new FileReader();
r.onload = (): void => {
FileHelper.uploadFile({
filename: file.name,
filepath: `${this.props.datastoreId}/${this.props.itemId}/${this.props.fieldId}/${file.name}`,
file: r.result,
field_id: this.props.fieldId,
item_id: this.props.itemId || '',
d_id: this.props.datastoreId || '',
p_id: this.props.projectId || '',
display_order: nbFile
}).subscribe()
};
r.readAsArrayBuffer (file);
}
So I get an RcFile (which just extend the type file) from that moment, I don't know what to do to get a raw binary of the file. my API only work with a raw binary, and nothing else. so I need that file: r.result, to be a pure binary raw data.
I found other stackoverflow question, but they all say how it should be (using base64 or other) but not how to do it if you have no other option to change it.
How can I achieve this ?
According to the file-upload tool you linked (ng-file-upload) you should first: "Ask questions on StackOverflow under the 'ng-file-upload' tag." So, add that tag to this post.
Then if I Ctrl+F for "binary" on the docs, I see this:
Upload.http({
url: '/server/upload/url',
headers : {
'Content-Type': file.type
},
data: file
})
Looks like they're passing a file object as the data, and the w/e the file type is in the header. I haven't tried this though...

How do I reuse the result arrays of Papa Parse?

I was reluctant to use Papa Parse, but now I realize how powerful it is. I am using Papa Parse on a local file, but I don't know how to use the results. I want to be able to use the results so I can combine the array with another and then sort highest to lowest based on a certain element. Console.log doesn't work. From what I have researched, it may have something to do with a callback function. I am stuck on how to do the callback function with Papa Parse. Thanks for any advice.
This is my output
Finished input (async).
Time: 43.90000000000873
Arguments(3)
0:
data:
Array(1136) [0 … 99]
0: (9) [
"CONTENT TYPE", "TITLE", "ABBR", "ISSN",
"e-ISSN", "PUBLICATION RANGE: START",
"PUBLICATION RANGE: LATEST PUBLISHED",
"SHORTCUT URL", "ARCHIVE URL"
]
1: (9) [
"Journals", "ACM Computing Surveys ",
"ACM Comput. Surv.", "0360-0300", "1557-7341",
"Volume 1 Issue 1 (March 1969)",
"Volume 46 Issue 1 (October 2013)",
"http://dl.acm.org/citation.cfm?id=J204",
"http://dl.acm.org/citation.cfm?id=J204&picked=prox"
]
Based on a conversation with you, it appears you're trying to retrofit the Papa Parse demo for your own needs. Below is a stripped down code snippet that should be drop-in-ready for your project and will get you started.
document.addEventListener('DOMContentLoaded', () => {
const file = document.getElementById('file');
file.addEventListener('change', () => {
Papa.parse(file.files[0], {
complete: function(results) {
// Here you can do something with results.data
console.log("Finished:", results.data);
}
});
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.6.2/papaparse.js"></script>
<input type="file" id="file" />
Original Answer
Since I suspect you're loading your local csv file from the files system, and not an upload form, you'll need to use download: true to make it work.
Papa.parse('data.csv', {
download: true,
complete: function(results) {
console.log("Finished:", results.data);
}
});
Technically, when loading local files, you're supposed to supply Papa.parse with a File Object. This is a snippet from MDN File API documentation
File objects are generally retrieved from a FileList object returned
as a result of a user selecting files using the input element
If of course you're running this in NodeJS, then you'd just do the following:
const fs = require('fs');
const Papa = require('papaparse');
const csv = fs.createReadStream('data.csv');
Papa.parse(csv, {
complete: function(results) {
console.log("Finished:", results);
}
});
Documentation
https://www.papaparse.com/docs#local-files
https://developer.mozilla.org/en-US/docs/Web/API/File

File length is undefined

Using the Filesystem API of Tizen SDK, I'm getting a javascript File object that prints the following datas on console.log:
File
created: Thu Dec 14 2017 09:59:51 GMT+0100 (CET)
fullPath: "/opt/share/folder/image.jpg"
get fileSize: function fileSizeGetter() {var _realPath=commonFS_.toRealPath(this.fullPath);var _result=native_.callSync('File_statSync',{location:_realPath});var _aStatObj=native_.getResultObject(_result);return _aStatObj.isFile?_aStatObj.size:undefined;}
isDirectory: false
isFile: true
length: undefined
mode: "rw"
modified: Thu Dec 14 2017 09:59:51 GMT+0100 (CET)
name: "image.jpg"
parent: File
path: "/opt/share/folder/"
readOnly: false
set fileSize: function () {}
__proto__: File
Problem is that the length of the File is undefined. This cause my Filereader readyState to stay at 0 (EMPTY) state (or maybe the problem is somewhere else).
Why is my code returning undefined for length parameter?
My code:
tizen.filesystem.resolve('/opt/share/folder/image.jpg', function(file) {
console.log(file);
var reader = new FileReader();
console.log(reader);
reader.readAsArrayBuffer(file);
reader.onload = fileLoad;
reader.onerror = function(evt){
console.log(evt.target.error.name);
}
});
Console value for reader:
FileReader
constructor: FileReaderConstructor
error: null
onabort: null
onerror: function (evt) {
onload: function fileLoad(evt) {
onloadend: null
onloadstart: null
onprogress: null
readyState: 0
result: null
__proto__: FileReaderPrototype
Precision:
Using the file url to insert image in a canvas is working and the file is existing on device
According to the documentation, length is for File instances representing directories (it tells you how many files and directories the directory contains). For a File actually representing a file, you'd use fileSize.
I don't see a FileReader anywhere in the Tizen file system documentation. Instead, examples reading and writing files use a FileStream via openStream.

Write EXIF data to image stream Node.js

I found a nice npm package that allows you to read and write Exif data to images, https://github.com/Sobesednik/node-exiftool.
The challenge that I have is that it requires you to provide the path to an image. So, the image has to be written to disk if you want to modify the EXIF using this package. Is there an easy way to check/read the EXIF, and if necessary, write EXIF data to an image stream?
var imageURL = 'https://nodejs.org/static/images/logos/nodejs-new-pantone-black.png'
var upstreamServer = 'http://someupstreamserver/uploads'
request
.get(imageURL)
.pipe(
// TODO read EXIF
// TODO write missing EXIF
request
.post(upstreamServer, function(err, httpResponse, body){
res.send(201)
})
)
EDIT: This question was also asked on node-exiftool
i had a similar task. I had to write physical dimensions and additional metadata to PNG files. I have found some solutions and combined it into one small library.
png-metadata
it could read PNG metadata from NodeJS Buffers, and create a new Buffers with new metadata.
Here is an example:
const buffer = fs.readFileSync('1000ppcm.png')
console.log(readMetadata(buffer));
withMetadata(buffer,{
clear: true, //remove old metadata
pHYs: { //300 dpi
x: 30000,
y: 30000,
units: RESOLUTION_UNITS.INCHES
},
tEXt: {
Title: "Short (one line) title or caption for image",
Author: "Name of image's creator",
Description: "Description of image (possibly long)",
Copyright: "Copyright notice",
Software: "Software used to create the image",
Disclaimer: "Legal disclaimer",
Warning: "Warning of nature of content",
Source: "Device used to create the image",
Comment: "Miscellaneous comment"
}
});
It could be modified to be used with streams, for example, you could implement WritableBufferStream class.
const { Writable } = require('stream');
/**
* Simple writable buffer stream
* #docs: https://nodejs.org/api/stream.html#stream_writable_streams
*/
class WritableBufferStream extends Writable {
constructor(options) {
super(options);
this._chunks = [];
}
_write(chunk, enc, callback) {
this._chunks.push(chunk);
return callback(null);
}
_destroy(err, callback) {
this._chunks = null;
return callback(null);
}
toBuffer() {
return Buffer.concat(this._chunks);
}
}

Chrome App Javascript: Save text as a DOCX file

I am aware that a DOCX file is essentially a zip full of XML files. Is there any simple way of using the chrome.fileSystem storage API to save a DOCX file, or would I have to create and package the XML files manually?
chrome.fileSystem.chooseEntry({
type: 'saveFile',
accepts: [
{ extensions: ['docx'] },
{ extensions: ['txt'] },
]
}, function(writableFileEntry) {
var ext = writableFileEntry.name.substr(writableFileEntry.name.lastIndexOf('.') + 1);
var text = document.getElementById("textarea").innerText;
if(ext == 'docx'){
... ?
}
else if(ext == 'txt'){
writableFileEntry.createWriter(function(writer) {
writer.write(new Blob([text], {type: 'text/plain'}));
}, function(){
window.alert('Saving file failed');
});
}
});
fileSystem API has nothing to do with specific file formats or compression - this is outside its scope. It's providing raw file access.
To do any kind of content formatting, you need to look for extra libraries or do it yourself, and then feed the resulting binary to fileSystem.

Categories

Resources