如何从 Meteor 中的文件夹中读取所有 JSON 个文件?

How can I read all JSON files from a folder in Meteor?

我想在我的 Meteor 应用程序中读取文件夹内的所有 json 个文件。

我有以下结构:

/server  
-- /methods  
-- -- file1.json  
-- -- file2.json  

我尝试使用以下代码读取所有 JSON 个文件:

var fs = Npm.require('fs');
var path = Npm.require('path');
var base = path.resolve('.');

try {
    var files = fs.readdirSync(base + '/methods/*.json');
    console.log(files);
} catch (e) {
    console.dir(e)
}

但这不起作用,它向我显示一个错误,指出该目录或文件不存在。

我是不是犯了什么错误?或者还有其他方法吗?

首先,请小心寻找 Meteor 的项目根目录,因为 path.resolve('.') 甚至 process.env.PWD 的结果可能会在不同的部署设置中发生变化。

其次,fs.readdirSync(path)的参数path需要一个目录。因此,正确的调用应该是 var files = fs.readdirSync(base + '/server/methods/');.

不过,我建议使用Assets. Just move your JSON files to your private directory and access them on the server via Assets.getText(assetPath, [asyncCallback]) or Assets.getBinary(assetPath, [asyncCallback])

例如:

if (Meteor.isServer) {
    Meteor.startup(function() {
        var example1 = JSON.parse(Assets.getText('methods/example1.json'));
        var example2 = JSON.parse(Assets.getText('methods/example2.json'));
        console.log(example1);
        console.log(example2);
    });
}

如果您想阅读 所有 JSON 个文件,您可能需要以下解决方法:

if (Meteor.isServer) {
    Meteor.startup(function() {
        var exec = Npm.require('child_process').exec;
        var files = [],
            fileNames = [];
        exec('ls -m assets/app/methods | tr -d \' \n\' ', Meteor.bindEnvironment(function(error, stdout, stderr) {
            if (error !== null) {
                console.log('exec error: ' + error);
            }
            fileNames = stdout.split(',');
            /* Print all file names. */
            console.log("File names:");
            console.log(fileNames);
            _.each(fileNames, function(fileName) {
                /* Check if file has proper extension. */
                if (fileName.split('.').pop() == 'json') files.push(JSON.parse(Assets.getText('methods/' + fileName)));
            });
            /* Print all JSON files. */
            _.each(files, function(file) {
                console.log(file);
            });
        }));
    });
}

如果要同步调用 exec,可能需要使用 Meteor.wrapAsync(func, [context]):

if (Meteor.isServer) {
    var exec = Npm.require('child_process').exec;
    var files = [], fileNames = [];

    var execAsync = function (options, callback) {
        console.log("execAsync()");
        exec('ls -m assets/app/methods | tr -d \' \n\' ', Meteor.bindEnvironment(function (error, stdout, stderr) {
            if (error !== null) {
                console.log('exec error: ' + error);
            }
            fileNames = stdout.split(',');
            /* Print all file names. */
            console.log("File names:");
            console.log(fileNames);
            _.each(fileNames, function (fileName) {
                /* Check if file has proper extension. */
                if (fileName.split('.').pop() == 'json') files.push(JSON.parse(Assets.getText('methods/' + fileName)));
            });
            callback(null, options.callback);
        }));
    };

    function postProcessing(callback) {
        console.log("postProcessing()");
        /* Print all JSON files. */
        _.each(files, function (file) {
            console.log(file);
        });
        callback();
    }

    Meteor.startup(function () {
        /*  Wrap asynchronous exec function, in order to call it in a synchronous style. */
        var execSync = Meteor.wrapAsync(execAsync);
        var refToPostProcessing = execSync({callback: postProcessing});
        var postProcessingSync = Meteor.wrapAsync(refToPostProcessing);
        postProcessingSync();
    });

}

这是我的服务器输出:

I20150919-09:27:09.189(2)? execAsync()        
I20150919-09:27:09.210(2)? File names:
I20150919-09:27:09.213(2)? [ 'example1.json', 'example2.json' ]
I20150919-09:27:09.215(2)? postProcessing()
I20150919-09:27:09.217(2)? { name: 'Product',
I20150919-09:27:09.217(2)?   properties: 
I20150919-09:27:09.218(2)?    { id: 
I20150919-09:27:09.218(2)?       { type: 'number',
I20150919-09:27:09.218(2)?         description: 'Product identifier',
I20150919-09:27:09.218(2)?         required: true },
I20150919-09:27:09.218(2)?      name: 
I20150919-09:27:09.218(2)?       { description: 'Name of the product',
I20150919-09:27:09.219(2)?         type: 'string',
I20150919-09:27:09.219(2)?         required: true },
I20150919-09:27:09.219(2)?      price: { type: 'number', minimum: 0, required: true },
I20150919-09:27:09.219(2)?      tags: { type: 'array', items: [Object] } } }
I20150919-09:27:09.220(2)? { red: '#f00',
I20150919-09:27:09.221(2)?   green: '#0f0',
I20150919-09:27:09.221(2)?   blue: '#00f',
I20150919-09:27:09.221(2)?   cyan: '#0ff',
I20150919-09:27:09.221(2)?   magenta: '#f0f',
I20150919-09:27:09.221(2)?   yellow: '#ff0',
I20150919-09:27:09.221(2)?   black: '#000' }

假设您有以下结构:

your-meteor-project
├── .meteor
├── server
├── private
│   └── methods
│       └── example1.json
│       └── example2.json
└── …

根据上面Matthias Eckhart的回答,我写了一个方法来加载一个文件夹中的所有csv文件,将内容转换为JSON和return数据作为一个带有子对象的客户端每个 csv 文件的对象。我 post 在这里以防它对其他人有所帮助:使用资产和方法以及将 csv 转换为 JSON.

时存在一些问题
import CSVToJSON from 'csvtojson';

if (Meteor.isServer) {
    const getParameterFilenames = (options, callback) => {
        // read the contents of the 'private/parameters' folder
        const { exec } = Npm.require('child_process');

        // "ls -m" will return directories as well as folders, so make sure to filter the results before loading files
        exec('ls -m assets/app/parameters | tr -d \' \n\' ', Meteor.bindEnvironment((error, stdout, stderr) => {
            if (error !== null) {
                console.log(`Error in getParameterFilenames: ${error}`);
            }
            const filenames = stdout.split(',');
            callback(null, filenames);
        }));
    };

    Meteor.methods({
        'loadParameters'() {
            const syncFunc = Meteor.wrapAsync(getParameterFilenames);
            const filenames = syncFunc({});
            // load parameters from csv files in 'private/parameters'
            // this will be assets/app/parameters in the built app

            // csv file contains key / value pairs
            // first row is key, second row is value
            // first key must be propertyName which will be the key for this sheet's child object in parameters, e.g.:

            /*
            "propertyName","value1","value2"
            "map",10,20
            */

            const promises = [];
            const filesData = [];

            // although Assets.getText is used synchronously, the files must be retrieved before creating the promises
            filenames.forEach((filename) => {
                if (filename.split('.').pop() === 'csv') {
                    filesData.push(Assets.getText(`parameters/${filename}`));
                }
            });

            filesData.forEach((data) => {
                promises.push(CSVToJSON().fromString(data));
            });

            // Meteor will wait for Promise.all to resolve before returning the result to the client
            return Promise.all(promises)
                .then((results) => {
                    // aggregate results into an object
                    const parameters = {};

                    results.forEach((result) => {
                        const data = result[0];
                        const parameter = { ...data };
                        delete parameter.propertyName;
                        parameters[data.propertyName] = parameter;
                    });

                    return parameters;
                });
        },
    });
}