Javascript,Nodejs:在文件中搜索特定的单词字符串

Posted

技术标签:

【中文标题】Javascript,Nodejs:在文件中搜索特定的单词字符串【英文标题】:Javascript,Nodejs: search for a specific word string in files 【发布时间】:2018-07-17 16:35:20 【问题描述】:

我正在尝试制作一个搜索所有文件的应用程序 包含当前目录/子目录下的指定字符串。

据我了解,这意味着我需要创建一个读取流,循环它,将读取的数据加载到一个数组中,如果找到的单词给出 __filename、dirname 和 if !未找到消息。

不幸的是,我无法让它工作...... 有什么线索吗?

var path = require('path'),
 fs=require('fs');

function fromDir(startPath,filter,ext)

    if (!fs.existsSync(startPath))
        console.log("no dir ",startPath);
        return;
    ;
    
    var files=fs.readdirSync(startPath);
    let found = files.find((file) => 
        let thisFilename = path.join(startPath, file);
        let stat = fs.lstatSync(thisFilename);
        var readStream = fs.createReadStream(fs);
        var readline = require('readline');
        if (stat.isDirectory()) 
            fromDir(thisFilename, filename,readline, ext);



         else 
            if (path.extname(createReadStream) === ext && path.basename(thisFilename, ext) === filename) 
                return true;
        
        
        );

       

            console.log('-- your word has found on : ',filename,__dirname);
        
     
    if (!found)  
        console.log("Sorry, we didn't find your term");
    

    
    
    fromDir('./', process.argv[3], process.argv[2]);
   

【问题讨论】:

您需要 readline,但您似乎没有使用它 doc。此外,您也可以使用 exec grep -rnw '/path/to/somewhere/' -e 'pattern' 之类的东西来代替。 fs.existsSync() ... fs.readdirSync() is an anti-pattern,因为它引入了(罕见但可能的)竞争条件。 【参考方案1】:

因为问题中没有包含所有内容,所以我做了一个假设:

我们正在寻找完整的单词(如果不是这样,请将正则表达式替换为简单的indexOf())。

现在,我将代码拆分为两个函数 - 使其更具可读性和更易于递归查找文件。

同步版本:

const path = require('path');
const fs = require('fs');

function searchFilesInDirectory(dir, filter, ext) 
    if (!fs.existsSync(dir)) 
        console.log(`Specified directory: $dir does not exist`);
        return;
    

    const files = getFilesInDirectory(dir, ext);

    files.forEach(file => 
        const fileContent = fs.readFileSync(file);

        // We want full words, so we use full word boundary in regex.
        const regex = new RegExp('\\b' + filter + '\\b');
        if (regex.test(fileContent)) 
            console.log(`Your word was found in file: $file`);
        
    );


// Using recursion, we find every file with the desired extention, even if its deeply nested in subfolders.
function getFilesInDirectory(dir, ext) 
    if (!fs.existsSync(dir)) 
        console.log(`Specified directory: $dir does not exist`);
        return;
    

    let files = [];
    fs.readdirSync(dir).forEach(file => 
        const filePath = path.join(dir, file);
        const stat = fs.lstatSync(filePath);

        // If we hit a directory, apply our function to that dir. If we hit a file, add it to the array of files.
        if (stat.isDirectory()) 
            const nestedFiles = getFilesInDirectory(filePath, ext);
            files = files.concat(nestedFiles);
         else 
            if (path.extname(file) === ext) 
                files.push(filePath);
            
        
    );

    return files;

异步版本 - 因为async 很酷:

const path = require('path');
const fs = require('fs');

const fsReaddir = util.promisify(fs.readdir);
const fsReadFile = util.promisify(fs.readFile);
const fsLstat = util.promisify(fs.lstat);

async function searchFilesInDirectoryAsync(dir, filter, ext)   
    const files = await fsReaddir(dir).catch(err => 
        throw new Error(err.message);
    );
    const found = await getFilesInDirectoryAsync(dir, ext);

    for (file of found) 
        const fileContent = await fsReadFile(file);

        // We want full words, so we use full word boundary in regex.
        const regex = new RegExp('\\b' + filter + '\\b');
        if (regex.test(fileContent)) 
            console.log(`Your word was found in file: $file`);
        
    ;


// Using recursion, we find every file with the desired extention, even if its deeply nested in subfolders.
async function getFilesInDirectoryAsync(dir, ext) 
    let files = [];
    const filesFromDirectory = await fsReaddir(dir).catch(err => 
        throw new Error(err.message);
    );

    for (let file of filesFromDirectory) 
        const filePath = path.join(dir, file);
        const stat = await fsLstat(filePath);

        // If we hit a directory, apply our function to that dir. If we hit a file, add it to the array of files.
        if (stat.isDirectory()) 
            const nestedFiles = await getFilesInDirectoryAsync(filePath, ext);
            files = files.concat(nestedFiles);
         else 
            if (path.extname(file) === ext) 
                files.push(filePath);
            
        
    ;

    return files;

如果您还没有使用/理解 async/await,那么尽快采取并学习它是一个很好的步骤。相信我,你会喜欢不再看到那些丑陋的回调!

更新: 正如您在 cmets 中指出的那样,您希望它在对文件运行 node 进程后执行该函数。您还希望将函数参数作为node 的参数传递。

为此,您需要在文件末尾添加:

searchFilesInDirectory(process.argv[2], process.argv[3], process.argv[4]);

这会提取我们的参数并将它们传递给函数。

这样,您可以像这样调用我们的流程(示例参数):

node yourscriptname.js ./ james .txt

就个人而言,如果我要写这篇文章,我会利用异步代码的美感,以及 Node.js 的 async / await

附带说明:

如果您添加正确的格式,您可以轻松提高代码的可读性。不要误会我的意思,这并不可怕 - 但可以改进:

    在逗号后使用空格或换行符。 在等式运算符和算术运算符周围使用空格。

只要格式一致,一切看起来都会好很多。

【讨论】:

嗨,您对代码的编辑在语法上没有错误,但我仍然无法在文件中找到任何单词。任何想法为什么?谢谢 你能告诉我你是如何使用它的吗?我对其进行了测试,它对我来说效果很好。 假设我在名为 232 的子文件夹中有 txt 文件,我想找到其中包含“james”一词的文件。我想输入 node search txt james 和 console.log 来告诉我哪些文件包含这个字符串。 我都明白。但是您需要更具体地了解到底发生了什么——当我在我的 PC 上本地运行它时,无论文件或子文件夹的数量如何,它都能很好地找到单词。我已经测试了静态文件路径和相对路径。 你不应该使用fs.exists[Sync],尤其是在你的异步版本中,因为it's an anti-pattern that introduces a race condition.

以上是关于Javascript,Nodejs:在文件中搜索特定的单词字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何在子目录中搜索特定文件?

如何在当前文件夹和所有子文件夹中的所有文件中搜索特定文件内容[重复]

是否可以在整个设备中搜索特定扩展名的文件?

在 FileNet 中搜索特定文件夹的文件夹层次结构

在目录中搜索特定文件名

C++ 在文本文件中搜索特定字符串并返回该字符串所在的行号