How to replace contents of file in a zip using JSzip? - javascript

I have been working on a project, I download a zip file from internet through XMLHttpRequest (type: blob ) and then I try to read its content using JSzip.So every zip has a json which I am interested in say manifest.json. So I was successful to read it with this code.
var read_zip = new JSZip();
res=xhr.response;
read_zip.loadAsync(xhr.response).then(function (zip) {
return zip.file("manifest.json").async("string");
}).then(function (text) {
obj = JSON.parse(text);
console.log(text);});
after this I made some changes to 'obj', Now I want to replace the existing manifest with this modified 'obj' json contents and save it.
I was trying this code
var write_zip = new JSZip();
write_zip.loadAsync(xhr.response).then(function (zip) {
zip.file("manifest.json" , obj) ;
zip.generateAsync({type:"blob"})
.then(function (blob) {
saveAs(blob, "hello.zip");
});});
but I am getting this error
Uncaught (in promise) Error: Can't read the data of 'manifest.json'.
Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc)
?
sorry, I am new to this.

It looks like you're trying to write an object into zip which is not supported. According to the documentation on JsZip the value to be written needs to be of type:
String/ArrayBuffer/Uint8Array/Buffer/Blob/Promise/Nodejs stream
See: JSZip#file(name, data [,options])

Related

Normalising the fileName in IE11 and creating of a new file in Javscript

I'm trying to upload a file, but i want to normalize it's name fisrt, it works on other browsers, but in IE11, i searched and i found out that this method (normalize) is not supported, so i'm using polyfill unorm. so normalizing works fine now, but we can't change the fileName directly, we need to create a new file. But we can't use new File because it's not supported too. So I used new Blob, but the problem is that i don't get the filename on the server side, it's always blob.
The code for other browsers :
var fileName = file.name.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
var newFile = new File([file], fileName, { type: file.type });
newFile.label = 'FICHIER';
The code for IE11
fileName = unorm.nfd(file.name);
newFile = new Blob([file], { type: file.type });
newFile.label = 'Fichier';
newFile.name= fileName;
To generate the request to the server, i use formdata :
fd = new FormData();
fd.append("id", param);
fd.append(file.label || "uploadedFile", file, file[paramName]);
Can you tell me what should i do to get the filename or if there is another way to do this.
The Blob object doesn't contain the name property, so, we can't change name via the Blob object.
After getting the file data, I suggest you could append a new parameter to log the new file name, then, when submits the form or save the uploaded file, you could send the file data and the new file name to the server.
Besides, here is another thread about upload file using FormData, please refer to it:
Angular File Upload
File Upload using AngularJS

Using FileReader to read a JSON file?

I'm trying to read a JSON file I have, uploaded by the user, and try to copy it to an array. However, with a .readAsText(), the return I get has the formatting of a string (obviously), such as including \" and \n and other string-like properties.
Is there a way I can use FileReader (or any other form of reading files, that don't involve a server) to read the JSON file and have it return just the plain JSON?
For example, having it return
[
{"hello": "world"}
]
or
[{"hello": "world"}]
and not
"[\n{\"hello\": \"world\"}\n]"
?
Edit: I am now aware of the JSON.parse(text) method, but I'm getting an error when parsing the FileReader object
let fileUploaded = new FileReader();
fileUploaded.readAsText(MY_JSON_FILE);
console.log(JSON.parse(fileUploaded));
it returns the error error TS2345: Argument of type 'FileReader' is not assignable to parameter of type 'string'
Can I get what i read with FileReader to another var that is a string, and then parse that new var?
The code at the question uses FileReader incorrectly.
FileReader .readAs<Type> operation is asynchronous. FileReader has load and loadend events where the result property of event.target and FileReader instance is the resulting asynchronously processed data.
Do not parse the FileReader object itself.
.readAs<Type> expects a Blob to be passed as parameter, not a JavaScript plain object.
const MY_JSON_FILE = [{
"hello": "world"
}];
let json = JSON.stringify(MY_JSON_FILE);
const blob = new Blob([json], {type:"application/json"});
const fr = new FileReader();
fr.addEventListener("load", e => {
console.log(e.target.result, JSON.parse(fr.result))
});
fr.readAsText(blob);

Get file type after sending the file from WebRTC

I am using WebRTC to get two clients communicated using peer.js
var peer = new Peer(
{
key: "XXX",
config: {"XXX": [{ url: "XXXXXXX" }]}
});
My main aim is to send file from one client to another. For that I am using following code:
$("#box").on("drop", function(e)
{
e.originalEvent.preventDefault();
var file = e.originalEvent.dataTransfer.files[0];
console.log(file);
connection.send(file);
});
On the receiving end I am using below code:
conn.on("data", function(data)
{
if (data.constructor === ArrayBuffer)
{
var dataView = new Uint8Array(data);
var dataBlob = new Blob([dataView]);
var reader = new window.FileReader();
reader.readAsText(dataBlob);
console.log(reader);
}
}
Now my problem is I want to get the file type so that I can save it in the proper format. I am using download.js to save the file.
It is not possible to get the type from the raw data except there is some file type/hint embedded in the data (e.g. ZIP, PDF). You should create you own protocol to send the filename as well.
What I did is to use the channel's protocol property to set the filename with extension to transfer these type of metadata information.
Note that a few weeks ago sending blobs wasn't fully supported in Chrome (at least in one of my example applications).

Append image file to form data - Cordova/Angular

I am using Anuglar, Ionic and Cordova in my current project, and I'm trying to POST FormData containing an image file to my server. Right now I'm using the cordova camera plugin to return a file path to the image on the device (ex: file://path/to/img). Once I have the file path I want to append the image file to a FormData object using the images file path. Here is my code right now.
var fd = new FormData();
fd.append('attachment', file);
fd.append('uuid', uuid);
fd.append('userRoleId', userRole);
The code above works when appending a file that is taken from an <input type='file'> but doesn't work when just given the file path on the device.
Basically the FormData is showing like this right now:
------WebKitFormBoundaryasdf
Content-Disposition: form-data; name="attachment";
file://path/to/img
and I want it to look like this
------WebKitFormBoundaryasdf
Content-Disposition: form-data; name="attachment"; filename="jesus-quintana.jpg"
Content-Type: image/jpeg
I found many different ways to upload the image using cordova FileTransfer and by converting the image to a base64 and then uploading it. But I couldn't find any simple ways of just grabbing the file by using the path and posting it within a form. I'm not very familiar with the File Api so any help would be appreciated
After some fiddling around I manage to figure out a pretty simple solution.
First I added the cordova file plugin then I use the code below
var fd = new FormData();
window.resolveLocalFileSystemURL(attachment.img, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var imgBlob = new Blob([ this.result ], { type: "image/jpeg" } );
fd.append('attachment', imgBlob);
fd.append('uuid', attachment.uuid);
fd.append('userRoleId', 12345);
console.log(fd);
//post form call here
};
reader.readAsArrayBuffer(file);
}, function(e){$scope.errorHandler(e)});
}, function(e){$scope.errorHandler(e)});
So I'm just creating a form and using FileReader to insert an ArrayBuffer to the Blob object and then append that to the form data. Hopefully this helps someone else looking for an easy way to do this.
You do need to send file content. With the HTML5 FileAPI you need to create a FileReader object.
Some time ago, I developed an application with cordova and I had to read some files, and I made a library called CoFS (first, by Cordova FileSystem, but it's working in some browsers).
It's on beta state, but I use it and works well. You can try to do some like this:
var errHandler = function (err) {
console.log("Error getting picture.", err);
};
var sendPicture = function (file) {
var fs = new CoFS();
fs.readFile(file, function (err, data) {
if (err) {
return errHandler(err);
}
var fd = new FormData();
fd.append('attachment', new Blob(data));
fd.append('uuid', uuid);
fd.append('userRoleId', userRole);
console.log("Data of file:" + data.toString('base64'));
// Send fd...
});
};
navigator.camera.getPicture(sendPicture, errHandler);
Sorry my poor english.
Your post was extremly helpful to fix my problem. I'm using Ionic 4 and trying to upload an image using standard http and file client. The key code for reference is here:
return this.file.readAsArrayBuffer(path, file).
then(blob => {
const imgBlob = new Blob([blob], { type: 'image/jpeg' } );
formData.append('image[file]', imgBlob);
return this.http.post(url, formData, headers).subscribe();
});
Hope it helps someone out there as it did for me.

Phonegap FileReader readAsText returns null but readAsDataURL works

I'm using Phonegap to download an archive, unzip it, then read the files. It's all working until I try and read the files as text. If I use readAsDataURL() then I get a whole heap of stuff logged to the console.
function( file ) {
console.log(file);
var reader = new FileReader();
reader.onloadend = function( evt ) {
console.log( evt.target.result );
};
reader.readAsDataURL( file );
}
If I use readAsText() I get null. The files range from 300KB to 1.4MB, but all files return null in the console.
reader.readAsText( file );
Why would one function return something and the other be null? Is there a limit on the text size it can read?
This is the file object that I'm logging before creating reader, that I'm applying the functions to (I've shortened the file name):
{
"name":"categories.json",
"fullPath":"/var/mobile/.../Documents/data/file.json",
"type":null,
"lastModifiedDate":1380535318000,
"size":382456
}
And this is the evt object for readAsText():
{
"type":"loadend",
"bubbles":false,
"cancelBubble":false,
"cancelable":false,
"lengthComputable":false,
"loaded":0,
"total":0,
"target":{
"fileName":"/var/mobile/.../Documents/data/file.json",
"readyState":2,
"result":"null",
"error":null,
"onloadstart":null,
"onprogress":null,
"onload":null,
"onerror":null,
"onabort":null
}
}
UPDATE: I've seen in the W3C spec for the File API that result would only be set to null if an error had occured. But I tried adding a reader.onerror() function, but that wasn't getting called.
If an error occurs during reading the blob parameter, set readyState
to DONE and set result to null. Proceed to the error steps.
http://www.w3.org/TR/FileAPI/#dfn-readAsText
You may have been grabbing the fileEntry instead of a fileObject. Assuming file was actually fileEntry, try this:
var
fileEntry = file, //for example clarity - assumes file from OP's file param
reader = new FileReader()
;
fileEntry.file( doSomethingWithFileObject );//gets the fileObject passed to it
function doSomethingWithFileObject(fileObject){
reader.onloadend = function(e){
doSomething(e.target.result); //assumes doSomething defined elsewhere
}
var fileAsText = reader.readAsText(fileObject);
}
Definitely an API that screams for cruft reduction.

Categories