Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Save files in Meteor

Create a Meteor app and put the client_/server_ files in a client/server directories. Also, create a public dir to save the uploaded files.

Template.example.events({
'change input': function(ev) {
_.each(ev.srcElement.files, function(file) {
Meteor.saveFile(file, file.name);
});
}
});
<template name="example">
<input type=file />
</template>
/**
* @blob (https://developer.mozilla.org/en-US/docs/DOM/Blob)
* @name the file's name
* @type the file's type: binary, text (https://developer.mozilla.org/en-US/docs/DOM/FileReader#Methods)
*
* TODO Support other encodings: https://developer.mozilla.org/en-US/docs/DOM/FileReader#Methods
* ArrayBuffer / DataURL (base64)
*/
Meteor.saveFile = function(blob, name, path, type, callback) {
var fileReader = new FileReader(),
method, encoding = 'binary', type = type || 'binary';
switch (type) {
case 'text':
// TODO Is this needed? If we're uploading content from file, yes, but if it's from an input/textarea I think not...
method = 'readAsText';
encoding = 'utf8';
break;
case 'binary':
method = 'readAsBinaryString';
encoding = 'binary';
break;
default:
method = 'readAsBinaryString';
encoding = 'binary';
break;
}
fileReader.onload = function(file) {
Meteor.call('saveFile', file.srcElement.result, name, path, encoding, callback);
}
fileReader[method](blob);
}
/**
* TODO support other encodings:
* http://stackoverflow.com/questions/7329128/how-to-write-binary-data-to-a-file-using-node-js
*/
Meteor.methods({
saveFile: function(blob, name, path, encoding) {
var path = cleanPath(path), fs = __meteor_bootstrap__.require('fs'),
name = cleanName(name || 'file'), encoding = encoding || 'binary',
chroot = Meteor.chroot || 'public';
// Clean up the path. Remove any initial and final '/' -we prefix them-,
// any sort of attempt to go to the parent directory '..' and any empty directories in
// between '/////' - which may happen after removing '..'
path = chroot + (path ? '/' + path + '/' : '/');
// TODO Add file existance checks, etc...
fs.writeFile(path + name, blob, encoding, function(err) {
if (err) {
throw (new Meteor.Error(500, 'Failed to save file.', err));
} else {
console.log('The file ' + name + ' (' + encoding + ') was saved to ' + path);
}
});
function cleanPath(str) {
if (str) {
return str.replace(/\.\./g,'').replace(/\/+/g,'').
replace(/^\/+/,'').replace(/\/+$/,'');
}
}
function cleanName(str) {
return str.replace(/\.\./g,'').replace(/\//g,'');
}
}
});
@tomstove

This comment has been minimized.

Show comment Hide comment
@tomstove

tomstove Oct 25, 2012

Works a charm mate. Cheers!

Works a charm mate. Cheers!

@everdaniel

This comment has been minimized.

Show comment Hide comment
@everdaniel

everdaniel Oct 26, 2012

Worked perfectly, thanks!

Worked perfectly, thanks!

@jcampb

This comment has been minimized.

Show comment Hide comment
@jcampb

jcampb Nov 8, 2012

I've got this working now with a button to trigger the upload rather than when the file is selected...but it refreshes the page when finished. Any suggestions on how to keep meteor from refreshing the page?

jcampb commented Nov 8, 2012

I've got this working now with a button to trigger the upload rather than when the file is selected...but it refreshes the page when finished. Any suggestions on how to keep meteor from refreshing the page?

@literarymachine

This comment has been minimized.

Show comment Hide comment
@literarymachine

literarymachine Nov 15, 2012

The page refresh occurs because Meteor is monitoring the public directory for file changes. I got around it as suggested here: http://stackoverflow.com/questions/13201723/generating-and-serving-static-files-with-meteor

The page refresh occurs because Meteor is monitoring the public directory for file changes. I got around it as suggested here: http://stackoverflow.com/questions/13201723/generating-and-serving-static-files-with-meteor

@crapthings

This comment has been minimized.

Show comment Hide comment
@crapthings

crapthings Nov 28, 2012

now i can upload file with these code, but after upload where to get my file ?

i use http://localhost:3000/filename_just_uploaded.jpg

but i cant get it

now i can upload file with these code, but after upload where to get my file ?

i use http://localhost:3000/filename_just_uploaded.jpg

but i cant get it

@bcholmes

This comment has been minimized.

Show comment Hide comment
@bcholmes

bcholmes Dec 6, 2012

Thanks for this.

You've reversed the names of two files (client_example.js and client_example.html), but otherwise it's really helpful.

bcholmes commented Dec 6, 2012

Thanks for this.

You've reversed the names of two files (client_example.js and client_example.html), but otherwise it's really helpful.

@JamieCzuy

This comment has been minimized.

Show comment Hide comment
@JamieCzuy

JamieCzuy Dec 8, 2012

Doesn't work for me on my Mac with the latest FireFox (17.0.1).

Firebug show error message: TypeError: ev.srcElement is undefined on line "_.each(ev.srcElement.files, function(file) {" in file: client_example.js.

It does work on Opera, Safari and Chrome. Thanks

Doesn't work for me on my Mac with the latest FireFox (17.0.1).

Firebug show error message: TypeError: ev.srcElement is undefined on line "_.each(ev.srcElement.files, function(file) {" in file: client_example.js.

It does work on Opera, Safari and Chrome. Thanks

@saada

This comment has been minimized.

Show comment Hide comment
@saada

saada Dec 18, 2012

Just works! Thank you!

saada commented Dec 18, 2012

Just works! Thank you!

@janpo

This comment has been minimized.

Show comment Hide comment
@janpo

janpo Dec 25, 2012

@JamieCzuy ev.currentTarget.files it's ok

janpo commented Dec 25, 2012

@JamieCzuy ev.currentTarget.files it's ok

@deltaepsilon

This comment has been minimized.

Show comment Hide comment
@deltaepsilon

deltaepsilon Dec 30, 2012

Thanks a lot for the gist. I was able to successfully upload files using this method, thought I did it a tad differently and for a more narrow use case.

https://gist.github.com/4413727

Thanks a lot for the gist. I was able to successfully upload files using this method, thought I did it a tad differently and for a more narrow use case.

https://gist.github.com/4413727

@ocombe

This comment has been minimized.

Show comment Hide comment
@ocombe

ocombe Mar 31, 2013

By the way, for IE10 compatibility you need to use an array buffer. Juste change line 30 in client_save_file.js, replace "blob" by "new Blob([blob])"

ocombe commented Mar 31, 2013

By the way, for IE10 compatibility you need to use an array buffer. Juste change line 30 in client_save_file.js, replace "blob" by "new Blob([blob])"

@davidworkman9

This comment has been minimized.

Show comment Hide comment
@davidworkman9

davidworkman9 Jun 3, 2013

Thanks for this! I have a problem though. (through localhost) it crashes Chrome (v27.0.1453.93) on Ubuntu 13.04 with large files(30 MB+). Haven't tested other platforms. Any guesses as to why this might be happening?

Thanks for this! I have a problem though. (through localhost) it crashes Chrome (v27.0.1453.93) on Ubuntu 13.04 with large files(30 MB+). Haven't tested other platforms. Any guesses as to why this might be happening?

@lardcanoe

This comment has been minimized.

Show comment Hide comment
@lardcanoe

lardcanoe Jun 16, 2013

From 0.6.0 you need to use Npm.require instead of meteor_bootstrap

fs = Npm.require('fs');

From 0.6.0 you need to use Npm.require instead of meteor_bootstrap

fs = Npm.require('fs');

@stegrams

This comment has been minimized.

Show comment Hide comment
@stegrams

stegrams Jul 25, 2013

A single regex for cleaning paths and names, for both windows and *nix, could be

return str.replace(/\.\.|\/|\\/g, ''); // And yes I know! Looks like library shelf

A single regex for cleaning paths and names, for both windows and *nix, could be

return str.replace(/\.\.|\/|\\/g, ''); // And yes I know! Looks like library shelf
@huevoncito

This comment has been minimized.

Show comment Hide comment
@huevoncito

huevoncito Jul 30, 2013

Thanks so much for this script. I have a little problem though. I've made it so that the function loops so multiple files can be uploaded at once, by clicking a button. Thing is, when I do more than 1 file, some of the files show up as 0kb in the public folder. As empty files they're useless to me. Ideas? Thanks again!

Thanks so much for this script. I have a little problem though. I've made it so that the function loops so multiple files can be uploaded at once, by clicking a button. Thing is, when I do more than 1 file, some of the files show up as 0kb in the public folder. As empty files they're useless to me. Ideas? Thanks again!

@jnthnmyrs

This comment has been minimized.

Show comment Hide comment
@jnthnmyrs

jnthnmyrs Aug 5, 2013

Thank you so much for this script!
I ended up needing using fs.writeFileSync instead of fs.writeFile.
For some reason, with fs.writeFile, it would only upload an empty file at first. You would then have to upload it again for it to finish the job. It was weird, but then @mike-engel suggested giving fs.writeFileSync a try and ka-bam!

Thank you so much for this script!
I ended up needing using fs.writeFileSync instead of fs.writeFile.
For some reason, with fs.writeFile, it would only upload an empty file at first. You would then have to upload it again for it to finish the job. It was weird, but then @mike-engel suggested giving fs.writeFileSync a try and ka-bam!

@Goddard

This comment has been minimized.

Show comment Hide comment
@Goddard

Goddard Aug 15, 2013

These does nothing. It doesn't give me an error or nothing, but I can't find the file.

Goddard commented Aug 15, 2013

These does nothing. It doesn't give me an error or nothing, but I can't find the file.

@flyingfisher

This comment has been minimized.

Show comment Hide comment
@flyingfisher

flyingfisher Sep 9, 2013

This would work after meteor update to 0.6.5 . The path is wrong.
I find a work round with process.env['PWD'].
Just put it before your path. like following:
chroot = Meteor.chroot || (process.env['PWD'] +'/public') ;

This would work after meteor update to 0.6.5 . The path is wrong.
I find a work round with process.env['PWD'].
Just put it before your path. like following:
chroot = Meteor.chroot || (process.env['PWD'] +'/public') ;

@andystiff

This comment has been minimized.

Show comment Hide comment
@andystiff

andystiff Oct 2, 2013

Thank you so much for this, I've tried three other examples and none worked or I misunderstood them. Working beautifully.

Thank you so much for this, I've tried three other examples and none worked or I misunderstood them. Working beautifully.

@BruceHubbard

This comment has been minimized.

Show comment Hide comment
@BruceHubbard

BruceHubbard Dec 4, 2013

I ran into problems using Meteor 6.6.3 where it wasn't saving files. Found this StackOverflow which resolved my problem (Error: ENOENT): http://stackoverflow.com/questions/18616151/fs-writefile-doesnt-work-on-meteor-0-6-5-1

Turns out you can't just use public/myFilename because Meteor changed what the root directory of your app is. When I used "../../../../../public/" it starting working properly.

I ran into problems using Meteor 6.6.3 where it wasn't saving files. Found this StackOverflow which resolved my problem (Error: ENOENT): http://stackoverflow.com/questions/18616151/fs-writefile-doesnt-work-on-meteor-0-6-5-1

Turns out you can't just use public/myFilename because Meteor changed what the root directory of your app is. When I used "../../../../../public/" it starting working properly.

@davidrinnan

This comment has been minimized.

Show comment Hide comment
@davidrinnan

davidrinnan Apr 15, 2014

works fine! after changing to Npm.require and changing the path to reflect new location of chroot in meteor. Beware that uploading to public causes a restart to happen on the server. You should create a folder suffixed by ~ like images~ this will work without meteor restarting or updating the client.

works fine! after changing to Npm.require and changing the path to reflect new location of chroot in meteor. Beware that uploading to public causes a restart to happen on the server. You should create a folder suffixed by ~ like images~ this will work without meteor restarting or updating the client.

@gabrielhpugliese

This comment has been minimized.

Show comment Hide comment
@gabrielhpugliese

gabrielhpugliese Apr 29, 2014

I've uploaded the example to a repo (it's coffee, sorry):
https://github.com/gabrielhpugliese/meteor-file-upload

I've uploaded the example to a repo (it's coffee, sorry):
https://github.com/gabrielhpugliese/meteor-file-upload

@tomitrescak

This comment has been minimized.

Show comment Hide comment
@tomitrescak

tomitrescak Jun 24, 2014

Hi, thanks for the code. Worked well on localhost, but then on production server it is failing for larger files. For files cca > 2MB after some time I receive "404 Error: Page not found" (from Firebug).

Any idea?

Hi, thanks for the code. Worked well on localhost, but then on production server it is failing for larger files. For files cca > 2MB after some time I receive "404 Error: Page not found" (from Firebug).

Any idea?

@piyushcoader

This comment has been minimized.

Show comment Hide comment
@piyushcoader

piyushcoader Aug 22, 2014

ev.srcElement.files doesnt works gives undefined

ev.srcElement.files doesnt works gives undefined

@stephentcannon

This comment has been minimized.

Show comment Hide comment
@stephentcannon

stephentcannon Sep 4, 2014

@piyushcoader try ev.currentTarget.files

@piyushcoader try ev.currentTarget.files

@raniafekry

This comment has been minimized.

Show comment Hide comment
@raniafekry

raniafekry Sep 29, 2014

I tried it but it doesn't save file to public folder , I have meteor 0.9.3 , changed to
chroot = Meteor.chroot || (process.env['PWD'] +'/public') ;
and
fs = Npm.require('fs');

any solutions

I tried it but it doesn't save file to public folder , I have meteor 0.9.3 , changed to
chroot = Meteor.chroot || (process.env['PWD'] +'/public') ;
and
fs = Npm.require('fs');

any solutions

@raniafekry

This comment has been minimized.

Show comment Hide comment
@raniafekry

raniafekry Sep 29, 2014

@gabrielhpugliese
I tried your example meteor-file-upload got this error
Errors prevented startup:

While building package iron-dynamic-template:
error: no such package: 'blaze'

@gabrielhpugliese
I tried your example meteor-file-upload got this error
Errors prevented startup:

While building package iron-dynamic-template:
error: no such package: 'blaze'

@icolR

This comment has been minimized.

Show comment Hide comment
@icolR

icolR Nov 7, 2014

Works for me on Meteor 1.0 replacing :
ev.srcElement.files -> ev.currentTarget.files
chroot = Meteor.chroot || 'public'; -> chroot = Meteor.chroot || (process.env['PWD'] +'/public') ;
fs = meteor_bootstrap.require('fs') -> fs = Npm.require('fs');

Thanks a lot !

icolR commented Nov 7, 2014

Works for me on Meteor 1.0 replacing :
ev.srcElement.files -> ev.currentTarget.files
chroot = Meteor.chroot || 'public'; -> chroot = Meteor.chroot || (process.env['PWD'] +'/public') ;
fs = meteor_bootstrap.require('fs') -> fs = Npm.require('fs');

Thanks a lot !

@michaellouieloria

This comment has been minimized.

Show comment Hide comment
@michaellouieloria

michaellouieloria Nov 28, 2014

add for meteor 1.0

Meteor.methods({
saveFile: function(blob, name, path, encoding) {
check(blob, Match.Any);
check(name, String);
check(path, String);
check(encoding, String);

add for meteor 1.0

Meteor.methods({
saveFile: function(blob, name, path, encoding) {
check(blob, Match.Any);
check(name, String);
check(path, String);
check(encoding, String);

@maheshbvv

This comment has been minimized.

Show comment Hide comment
@maheshbvv

maheshbvv Dec 13, 2014

I am on meteor 1.0,

Chrome && Opera thowing an error shown below..

Uncaught TypeError: Cannot read property 'files' of undefined

When I tried on Firefox : Error is shown below

TypeError: ev.srcElement is undefined

please help

I am on meteor 1.0,

Chrome && Opera thowing an error shown below..

Uncaught TypeError: Cannot read property 'files' of undefined

When I tried on Firefox : Error is shown below

TypeError: ev.srcElement is undefined

please help

@rajeshtamire

This comment has been minimized.

Show comment Hide comment
@rajeshtamire

rajeshtamire Dec 19, 2014

it worked perfectly for me...Thanks!

it worked perfectly for me...Thanks!

@typista

This comment has been minimized.

Show comment Hide comment
@typista

typista Dec 25, 2014

TypeError: ev.srcElement is undefined

Works for me on Meteor 1.0.1 and 1.0.2 replacing :

client_save_file.js
30 //Meteor.call('saveFile', file.srcElement.result, name, path, encoding, callback);
31 Meteor.call('saveFile', file.target.result, name, path, encoding, callback);

typista commented Dec 25, 2014

TypeError: ev.srcElement is undefined

Works for me on Meteor 1.0.1 and 1.0.2 replacing :

client_save_file.js
30 //Meteor.call('saveFile', file.srcElement.result, name, path, encoding, callback);
31 Meteor.call('saveFile', file.target.result, name, path, encoding, callback);

@wontonst

This comment has been minimized.

Show comment Hide comment
@wontonst

wontonst Feb 22, 2015

Can't get this to work in Meteor 1.0.3. Made fixes in comment list. Fails silently without file being written to disk. Permissions are properly set.

Can't get this to work in Meteor 1.0.3. Made fixes in comment list. Fails silently without file being written to disk. Permissions are properly set.

@anuragarya

This comment has been minimized.

Show comment Hide comment
@anuragarya

anuragarya May 4, 2015

I am on Meteor 1.1.0.2 & I get following exception:
Exception while invoking method 'saveFile' TypeError: Object # has no method 'require'

I am on Meteor 1.1.0.2 & I get following exception:
Exception while invoking method 'saveFile' TypeError: Object # has no method 'require'

@Cerealkillerway

This comment has been minimized.

Show comment Hide comment
@Cerealkillerway

Cerealkillerway Jun 1, 2015

with meteor 1.1.0.2 works perfect for me, thank you;
the only thing I've changed is
fs = __meteor_bootstrap__.require('fs')
with
fs = Npm.require('fs')
inside the method

with meteor 1.1.0.2 works perfect for me, thank you;
the only thing I've changed is
fs = __meteor_bootstrap__.require('fs')
with
fs = Npm.require('fs')
inside the method

@ghost

This comment has been minimized.

Show comment Hide comment
@ghost

ghost Nov 20, 2015

the given code is not wokring.
HTML code is written in js file
and js file is written in html file. Blunder mistake

Do you have anywhere full source code where save file is working?

Any one there?

ghost commented Nov 20, 2015

the given code is not wokring.
HTML code is written in js file
and js file is written in html file. Blunder mistake

Do you have anywhere full source code where save file is working?

Any one there?

@manusharma1

This comment has been minimized.

Show comment Hide comment
@manusharma1

manusharma1 Jun 11, 2016

How to change this code to fs write stream, as it is not perfect for Bigger Uploads?, Can you suggest something?

How to change this code to fs write stream, as it is not perfect for Bigger Uploads?, Can you suggest something?

@maitrid

This comment has been minimized.

Show comment Hide comment
@maitrid

maitrid Aug 12, 2016

After looking into different possible solutions to file uploads with Meteor 1.3 and React, I couldn't find a suitable solution. This script helped a great deal. I can upload after a few small tweaks. Of course, for Meteor 1.3 and 1.4, it works without an error after installing fs rather than using fs = Npm.require('fs'):

meteor npm install --save fs

Then, in the server_save_files.js, I added this line on the top:

import fs from 'fs';

Next thing to figure out is: How to implement a progress bar for the upload?

maitrid commented Aug 12, 2016

After looking into different possible solutions to file uploads with Meteor 1.3 and React, I couldn't find a suitable solution. This script helped a great deal. I can upload after a few small tweaks. Of course, for Meteor 1.3 and 1.4, it works without an error after installing fs rather than using fs = Npm.require('fs'):

meteor npm install --save fs

Then, in the server_save_files.js, I added this line on the top:

import fs from 'fs';

Next thing to figure out is: How to implement a progress bar for the upload?

@saravanan4514

This comment has been minimized.

Show comment Hide comment
@saravanan4514

saravanan4514 Aug 13, 2016

Need to make the following changes to have this working in meteor 1.3

  1. import fs from 'fs'; (instead of fs = meteor_bootstrap.require('fs'))
  2. Change chroot to chroot = '../../../../../public';
  3. In helper function change the ev.srcElement.files to ev.currentTarget.files

Works like a charm after that. Thanks for the tutorial.

Need to make the following changes to have this working in meteor 1.3

  1. import fs from 'fs'; (instead of fs = meteor_bootstrap.require('fs'))
  2. Change chroot to chroot = '../../../../../public';
  3. In helper function change the ev.srcElement.files to ev.currentTarget.files

Works like a charm after that. Thanks for the tutorial.

@varunajmera0

This comment has been minimized.

Show comment Hide comment
@varunajmera0

varunajmera0 Mar 2, 2017

code is not working. :(

code is not working. :(

@varunajmera0

This comment has been minimized.

Show comment Hide comment
@varunajmera0

varunajmera0 Mar 2, 2017

image
i am getting error that meteor_bootstrap.require('fs') is not function.

image
i am getting error that meteor_bootstrap.require('fs') is not function.

@varunajmera0

This comment has been minimized.

Show comment Hide comment
@varunajmera0

varunajmera0 Mar 2, 2017

# Thanks alot man #dariocravero

Working.
Without any package.

Thanks

# Thanks alot man #dariocravero

Working.
Without any package.

Thanks

@varunajmera0

This comment has been minimized.

Show comment Hide comment
@varunajmera0

varunajmera0 Mar 2, 2017

can anyone tell how to create persistence storage in development mode for meteor. Whenever server starts either remove data or give this error
Error: EBUSY: resource busy or locked, rmdir 'C:\Users\admins\Desktop\tripsy\dummy.meteor\local\build\programs\server'
at Error (native)

can anyone tell how to create persistence storage in development mode for meteor. Whenever server starts either remove data or give this error
Error: EBUSY: resource busy or locked, rmdir 'C:\Users\admins\Desktop\tripsy\dummy.meteor\local\build\programs\server'
at Error (native)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment