Поиск…
замечания
Пакет CollectionFS был отложен и прекращен автором; однако, поскольку нет альтернативного пакета в Атмосфере или экосистеме Метеор для использования функции Mongo GridFS, и код все еще работает отлично; мы рекомендуем не удалять этот пример из документации StackOverflow до тех пор, пока какое-либо другое решение GridFS не будет задокументировано как замена.
Дополнительные исследования
Загрузка файлов и изображений
Файл сохранения файла Dario
Образец загрузки файла Micha Roon
Пакет загрузки файлов EventedMind
Сервер / Клиент
Загрузка файлов может быть легкой или очень сложной, в зависимости от того, что вы хотите делать. В общем, передача самого файла не так уж трудна. Но есть множество краевых случаев вокруг вложений, двоичных файлов и тому подобного. И реальная точка прилипания - горизонтальное масштабирование и создание решения, которое работает, когда сервер клонируется второй, третий и n-й раз.
Начнем с базовой модели загрузки сервера / клиента. Начнем с добавления элемента ввода файла в объектную модель документа.
<template name="example"> <input type=file /> </template>
Затем присоедините событие к элементу ввода внутри вашего контроллера и вызовите локальный метод Meteor `` startFileTransfer '', чтобы инициировать передачу.
// client/example.js Template.example.events({ 'change input': function(ev) { _.each(ev.srcElement.files, function(file) { Meteor.startFileTransfer(file, file.name); }); } }); // client/save.js /** * @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.startFileTransfer = 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('saveFileToDisk', file.srcElement.result, name, path, encoding, callback); } fileReader[method](blob); }
Затем клиент вызовет метод сервера saveFileToDisk, который выполняет фактическую передачу и помещает все на диск.
// /** * TODO support other encodings: * http://stackoverflow.com/questions/7329128/how-to-write-binary-data-to-a-file-using-node-js */ Meteor.methods({ saveFileToDisk: 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,''); } } });
Это своего рода подход с голыми костями, и это оставляет желать лучшего. Возможно, это полезно для загрузки CSV-файла или чего-то еще, но это все.
Dropzone (с железом: маршрутизатор)
Если нам нужно что-то более отполированное, с интегрированным интерфейсом Dropzone и конечной точкой REST, нам нужно будет начать добавлять пользовательские маршруты и пакеты REST с помощью помощников пользовательского интерфейса.
Начнем с импорта Iron Router и Dropzone.
meteor add iron:router
meteor add awatson1978:dropzone
И настройте URL-адрес загружаемого URL-адреса, указанный в помощнике dropzone.
Router.map(function () {
this.route('uploads', {
where: 'server',
action: function () {
var fs = Npm.require('fs');
var path = Npm.require('path');
var self = this;
ROOT_APP_PATH = fs.realpathSync('.');
// dropzone.js stores the uploaded file in the /tmp directory, which we access
fs.readFile(self.request.files.file.path, function (err, data) {
// and then write the file to the uploads directory
fs.writeFile(ROOT_APP_PATH + "/assets/app/uploads/" +self.request.files.file.name, data, 'binary', function (error, result) {
if(error){
console.error(error);
}
if(result){
console.log('Success! ', result);
}
});
});
}
});
});
Здорово! У нас есть файловый загрузчик с потрясающим интерфейсом и программируемой конечной точкой REST. К сожалению, это не очень хорошо масштабируется.
Filepicker.io
Чтобы масштабировать ситуацию, мы должны прекратить использование локального хранилища на нашем сервере и начать использовать либо специализированную службу хранения файлов, либо реализовать горизонтальный уровень хранения. Самый простой способ начать работу с масштабируемым хранилищем файлов - использовать такое решение, как Filepicker.io, которое поддерживает S3, Azure, Rackspace и Dropbox. loadpicker был популярным Unipackage Filerpicker на некоторое время.
meteor add mrt:filepicker
Шаблон Filepicker отличается от других решений, потому что это действительно о сторонней интеграции. Начните с добавления ввода filepicker, который, как вы увидите, в значительной степени зависит от атрибутов data- *, что довольно необычно для приложений Meteor.
<input type="filepicker" id="filepickerAttachment" data-fp-button-class="btn filepickerAttachment" data-fp-button-text="Add image" data-fp-mimetypes="image/*" data-fp-container="modal" data-fp-maxsize="5000000" data-fp-services="COMPUTER,IMAGE_SEARCH,URL,DROPBOX,GITHUB,GOOGLE_DRIVE,GMAIL">
Вы также захотите установить ключ API, построить виджет filepicker, запустить его и наблюдать за его результатами.
if(Meteor.isClient){ Meteor.startup(function() { filepicker.setKey("YourFilepickerApiKey"); }); Template.yourTemplate.rendered = function(){ filepicker.constructWidget($("#filepickerAttachment")); } Template.yourTemplate.events({ 'change #filepickerAttachment': function (evt) { console.log("Event: ", evt, evt.fpfile, "Generated image url:", evt.fpfile.url); }); });
CollectionFS
Однако, если вы действительно серьезно относитесь к хранилищу и хотите хранить миллионы изображений, вам понадобится использовать инфраструктуру GridFS Mongo и создать себе уровень хранения. Для этого вам понадобится отличная подсистема CollectionFS.
Начните с добавления необходимых пакетов.
meteor add cfs:standard-packages
meteor add cfs:filesystem
И добавление элемента загрузки файла в вашу объектную модель.
<template name="yourTemplate"> <input class="your-upload-class" type="file"> </template>
Затем добавьте контроллер событий на клиенте.
Template.yourTemplate.events({
'change .your-upload-class': function(event, template) {
FS.Utility.eachFile(event, function(file) {
var yourFile = new FS.File(file);
yourFile.creatorId = Meteor.userId(); // add custom data
YourFileCollection.insert(yourFile, function (err, fileObj) {
if (!err) {
// do callback stuff
}
});
});
}
});
И определите свои коллекции на своем сервере:
YourFileCollection = new FS.Collection("yourFileCollection", {
stores: [new FS.Store.FileSystem("yourFileCollection", {path: "~/meteor_uploads"})]
});
YourFileCollection.allow({
insert: function (userId, doc) {
return !!userId;
},
update: function (userId, doc) {
return doc.creatorId == userId
},
download: function (userId, doc) {
return doc.creatorId == userId
}
});
Благодаря Raz за этот отличный пример. Для получения более подробной информации о том, что может сделать все CollectionFS, вы захотите ознакомиться с полной сборкой CollectionFS.
Загрузка серверов
Следующие сценарии предназначены для загрузки файла из файловой системы сервера на сервер. В основном для файлов конфигурации и файловых шаблонов.
//https://forums.meteor.com/t/read-file-from-the-public-folder/4910/5
// Asynchronous Method.
Meteor.startup(function () {
console.log('starting up');
var fs = Npm.require('fs');
// file originally saved as public/data/taxa.csv
fs.readFile(process.cwd() + '/../web.browser/app/data/taxa.csv', 'utf8', function (err, data) {
if (err) {
console.log('Error: ' + err);
return;
}
data = JSON.parse(data);
console.log(data);
});
});
// Synchronous Method.
Meteor.startup(function () {
var fs = Npm.require('fs');
// file originally saved as public/data/taxa.csv
var data = fs.readFileSync(process.cwd() + '/../web.browser/app/data/taxa.csv', 'utf8');
if (Icd10.find().count() === 0) {
Icd10.insert({
date: new Date(),
data: JSON.parse(data)
});
}
});
Meteor.methods({
parseCsvFile:function (){
console.log('parseCsvFile');
var fs = Npm.require('fs');
// file originally saved as public/data/taxa.csv
var data = fs.readFileSync(process.cwd() + '/../web.browser/app/data/taxa.csv', 'utf8');
console.log('data', data);
}
});