如何使用FileSystem和CollectionFS将文件保存到文件夹中?

3

我觉得我缺了些什么。我已经阅读了很多帖子/示例,但是我无法在我的系统上保存图像(我在本地工作)。

我的目标是什么?

我试图将用户提交的文件保存在文件夹中(服务器端)。听起来容易吗?也许是。

问题出在哪里?

简短的回答:我无法弄清如何将文件保存在我的文件夹中。 需要更多信息吗?

一个文件上传的故事

我读到过,要像new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })一样使用path参数,我必须在服务器端声明我的集合。但是当我调用Avatars.insert()(Avatars是我的集合名称)时,它似乎不存在。这是有道理的,因为此集合仅存在于服务器上。

所以我尝试在服务器端和客户端都声明集合(我读了一些关于那方面的示例),并且它奏效了!文件已正确添加到MongoDB,但我的文件夹仍然为空(我不确定,但我认为这是因为Avatars.insert()被客户端调用,因此使用的是客户端集合,该集合无法使用path参数)。

但是没问题!我创建了2个Meteor方法(一个是客户端,一个是服务器端),名为“updateAvatarFile”。通过这种“技巧”,我能够执行Meteor.call("updateAvatarFile", field.files[0]),它会同时调用服务器端和客户端方法。因此,我可以在客户端执行一些UI操作,在另一个方法中上传文件。但是我无法将文件作为参数传递。

field.files[0]包含客户端的文件,但服务器端为空对象。我的问题是:我该如何上传文件?

我无法在客户端执行此操作(因为我无法使用path参数),但我可以将文件传递到服务器端。我确定我错过了什么,但我想不出来是什么。

以下是我的步骤:

// /client/views/templates/settings.js
Template.settings.events({
   'submit #updateAvatar': function (e, template) {
        e.preventDefault();
        const field = document.getElementsByName('avatar')[0];
        Meteor.call('updateAvatarFile', field.files[0]);
    }
});

// /client/lib/clientMethods.js
Meteor.methods({
    'updateAvatarFile': function (file) {
        // blabla
    }
});

// /server/lib/serverMethods.js
Meteor.methods({
    'updateAvatarFile': function (file) {
        Avatars.insert(file, function (err, fileObj) {
            if (err) {
                console.log(err);
            } else {
                console.log(fileObj);
            }
        });
    }
});

// /server/collections/serverAvatarCollection.js
Avatars = new FS.Collection("avatars", {
    stores: [
        new FS.Store.FileSystem("original", { path: "/public/images/user/avatar" }),
        new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })
    ],
    filter: {
        maxSize: 1000000, //1Mo
        allow: { contentTypes: ['image/*'] }
    },
    onInvalid: function (message) {
        //throw new Meteor.Error(403, message);
    }
});

// /client/collections/clientAvatarCollection.js
// (this one is actually in a comment block)
Avatars = new FS.Collection("avatars", {
    stores: [
        new FS.Store.FileSystem("original"),
        new FS.Store.FileSystem("thumb")
    ],
    filter: {
        maxSize: 1000000, //1Mo
        allow: { contentTypes: ['image/*'] }
    },
    onInvalid: function (message) {
        alert(message);
    }
});

我也尝试使用客户端方法插入文件,但结果相同(文件被添加到MongoDB,但未保存到文件夹中)。

使用不同的path值也没有效果。


编辑:或者我正在尝试使用错误的软件包?在我看来,将图片转换为块并将它们保存到MongoDB听起来真的很奇怪和糟糕。你有什么建议吗?


编辑2: 回答Michel Floyd的问题(对此表示抱歉,字符限制很烦人)。

首先,感谢您的回答!

1. 目前,我只是尝试Meteor,所以我安装了autopublishinsecure。不发布/订阅我的集合可能不会引起问题,对吗?

2. 在您的回答之前,我已经尝试设置一个可供服务器和客户端使用的集合,将我的avatarCollection.js放在/collections中。我认为不包含serverclient的路径自动适用于两侧。那么/collections/lib之间有什么区别?(我知道“lib”文件夹中的所有文件都会首先加载)。将集合放在/collections中是一种不好的做法吗?也许我应该创建一个/lib/collections文件夹?

3. (最后一点,对于这条长评论表示抱歉)我尝试了您上面建议的内容,但似乎不起作用(或者我又做错了什么><)。当我使用Avatars.insert()时,CollectionFS不会将文件保存在我的本地存储器中。我还检查了我的HDD根目录,以防CollectionFS将/解释为我的机器根目录,但它没有。另一方面,CollectionFS在MongoDB中创建了4个集合(cfs._tempstore.chunkscfs.avatars.filerecordcfs_gridfs._tempstore.chunkscfs_gridfs._tempstore.files)- gridfs很奇怪。我安装了GridFS,但我使用FileSystem-. 这些表不是空的。这就是为什么我认为CollectionFS将我的文件分成块并将它们保存在MongoDB中。

1个回答

1
您通常是在正确的轨道上。 CollectionFS使用存储适配器来处理实际的文件存储。您可以将文件放入S3、gridFS或本地文件系统中,就像您正在尝试的那样。通常避免直接将文件内容放入Mongo中。
首先,定义您的集合:
Avatars = new FS.Collection("avatars", {
    stores: [
        new FS.Store.FileSystem("original", { path: "/public/images/user/avatar" }),
        new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })
    ],
    filter: {
        maxSize: 1000000, //1Mo
        allow: { contentTypes: ['image/*'] }
    },
    onInvalid: function (message) {
        //throw new Meteor.Error(403, message);
    }
});

/lib目录下!这将使其对服务器和客户端都可用。
其次,请确保从服务器发布并从客户端订阅您的头像集合。我在您的问题中没有看到任何发布/订阅代码。您需要它。
第三,如果您只是执行以下操作:
Avatars.insert(...);

如果您在客户端使用文件,那么 CollectionFS 将会为您处理存储。问题是,它不会立即可用。实际上传和存储需要一些时间。例如,您可以查看 fileObj.isUploaded 来查看文件是否已准备好。

非常感谢您的回答。我已经编辑了我的原始帖子来回复。 - Armelias
  1. 如果您启用了自动发布,则发布不是您的问题。
  2. 您关于Meteor将非特殊目录中的文件发送到客户端和服务器的说法是正确的。
  3. tempstore目录仅在文件块临时传输到存储适配器时使用。
- Michel Floyd
抱歉耽搁了。问题是文件块没有进入存储适配器(文件系统)。我的文件夹是空的,即使我向集合中插入了一些东西。 - Armelias
你可以直接在Github项目上向CollectionFS的开发者询问文件系统适配器的问题。我曾经使用过它来连接S3和本地文件系统,一直都很稳定。 - Michel Floyd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接