写了小工具分享:按关键字文件在数据文件中搜索数据行

hongwenjun 2013-10-12 12:25:18
加精

 #include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void help(); // 帮助
BOOL IsFileExist(LPCTSTR lpFileName); // 检查一个文件是否存在

int main(int argc, char* argv[])
{
if ((1 == argc) || (2 == argc)) { //错误输入处理
help();
return -1;
} else if (!(IsFileExist(argv[1]) && IsFileExist(argv[2]))) {
printf("文件错误:检查文件是否存在!\n");
return -1;
}

FILE* keyfile = fopen(argv[1], "r"); // 关键字输入文件
if (ferror(keyfile)) {
printf("文件错误:不能打开输入文件: %s \n", argv[2]);
return -1;
}

char key_value[255];
char cmd_line[512] = {0};

while (!feof(keyfile)) { // 读取每一行关键字
if (fscanf(keyfile, "%s", key_value) == EOF)
return 0;
printf("查找: %s-->\n", key_value);

// 默认cmd_line调用命令: find /N "key_value" log.txt
sprintf(cmd_line, "find /N \"%s\" %s", key_value, argv[2]);

// 扩展选项[/C或/E], /C 仅显示包含字符串的行数。 /E 调用Grep工具,支持正则公式
if ((4 == argc) || (5 == argc)) {
char option = toupper(argv[3][1]);
if (option == 'C')
sprintf(cmd_line, "find /C \"%s\" %s", key_value, argv[2]);
if (option == 'E') {
sprintf(cmd_line, "grep -i -n \"%s\" %s", key_value, argv[2]);
if (5 == argc)
strcat(cmd_line, " | wc -l"); // Grep工具统计参数
}
}
int ret = system(cmd_line); // 每次的搜索结果
if (ret != 0)
printf("没有找到: %s <--\n", key_value);

printf("\n");
}

return 0;
}


// 检查一个文件是否存在
BOOL IsFileExist(LPCTSTR lpFileName)
{
WIN32_FIND_DATA fd = {0};
HANDLE hFind = FindFirstFile(lpFileName, &fd);
if (hFind != INVALID_HANDLE_VALUE) {
FindClose(hFind);
}
return ((hFind != INVALID_HANDLE_VALUE) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
}

void help()
{
printf("本工具可以按关键字文件在数据文件中搜索数据行 BY Hong Wenjun\n");

printf("选项 /C 仅显示包含字符串的行数; /E 调用Grep工具m支持正则公式\n");
printf("\n示例: D:\\>MultiFind.exe keyfile.txt log.txt [/C或/E]\n");
}
...全文
4344 46 打赏 收藏 转发到动态 举报
写回复
用AI写文章
46 条回复
切换为时间正序
请发表友善的回复…
发表回复
Bird_1989 2013-11-26
  • 打赏
  • 举报
回复
可以先MARK
bountiful 2013-11-23
  • 打赏
  • 举报
回复
正想学习关于搜索方面的算法
瘦又美 2013-10-21
  • 打赏
  • 举报
回复
不懂必须要问 2013-10-21
  • 打赏
  • 举报
回复
短短几句在,就知道楼主年薪过亿……
「已注销」 2013-10-19
  • 打赏
  • 举报
回复
既然都写代码了,那就不要再调用find了,自己实现吧
hongwenjun 2013-10-19
  • 打赏
  • 举报
回复
grep -n -fkeyfile.txt log.txt -c 就可以获得我想要的结果,而且已经去除重复了
grep -n -fkeyfile.txt log.txt -c
25


MultiFind.exe keyfile.txt log.txt /e /c
查找: 00070-043015-->
      2

查找: 00090-010818-->
      5

查找: 00060-044825-->
      3

查找: velour_00071-041888-->
      0

查找: velour_00071-041510-->
      1

查找: 00060-\d*-->
     25
5. Grep命令选项

-?
同时显示匹配行上下的?行,如:grep -2 pattern filename同时显示匹配行的上下2行。

-b,--byte-offset
打印匹配行前面打印该行所在的块号码。

-c,--count
只打印匹配的行数,不显示匹配的内容。

-f File,--file=File
从文件中提取模板。空文件中包含0个模板,所以什么都不匹配。

-h,--no-filename
当搜索多个文件时,不显示匹配文件名前缀。

-i,--ignore-case
忽略大小写差别。

-q,--quiet
取消显示,只返回退出状态。0则表示找到了匹配的行。

-l,--files-with-matches
打印匹配模板的文件清单。

-L,--files-without-match
打印不匹配模板的文件清单。

-n,--line-number
在匹配的行前面打印行号。

-s,--silent
不显示关于不存在或者无法读取文件的错误信息。

-v,--revert-match
反检索,只显示不匹配的行。

-w,--word-regexp
如果被\<和\>引用,就把表达式做为一个单词搜索。

-V,--version
显示软件版本信息。

6. 实例

要用好grep这个工具,其实就是要写好正则表达式,所以这里不对grep的所有功能进行实例讲解,只列几个例子,讲解一个正则表达式的写法。

$ ls -l | grep '^a'
通过管道过滤ls -l输出的内容,只显示以a开头的行。

$ grep 'test' d*
显示所有以d开头的文件中包含test的行。

$ grep 'test' aa bb cc
显示在aa,bb,cc文件中匹配test的行。

$ grep '[a-z]\{5\}' aa
显示所有包含每个字符串至少有5个连续小写字符的字符串的行。

$ grep 'w\(es\)t.*\1' aa
如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着另外一个es(\1),找到就显示该行。如果用egrep或grep -E,就不用"\"号进行转义,直接写成'w(es)t.*\1'就可以了。
hongwenjun 2013-10-19
  • 打赏
  • 举报
回复
引用 47 楼 jha334201553 的回复:
既然都写代码了,那就不要再调用find了,自己实现吧
抛砖引玉,希望你也能有所想法,让大家学习一下 谢谢 赵老师的 提供 findstr ,相当于 grep ,支持正则,效率也不错。 而且 findstr 和 grep 都可以实现 从一个文本文件里遍历关键字,如果我开始知道有这个功能 可能我就不会写上面这个代码了 8楼 有使用 strstr 普通搜索,比 find 效率要高。 使用 VC2010 的正则,使用起来也不是很难。 --------------------------------------------- 但是 如果都自己实现,可能代码就比较长,阅读起来就麻烦点了。
wjlsmail 2013-10-18
  • 打赏
  • 举报
回复
support layer8
yoursummer1991 2013-10-18
  • 打赏
  • 举报
回复
谢谢分享哦~
wayne_woo11 2013-10-17
  • 打赏
  • 举报
回复
当然支持,谢谢分享!
yushen_ye 2013-10-16
  • 打赏
  • 举报
回复
当然支持,谢谢分享!
ls1105 2013-10-16
  • 打赏
  • 举报
回复
不懂啊
fuyang100 2013-10-15
  • 打赏
  • 举报
回复
高手啊。。。。
jn9964 2013-10-15
  • 打赏
  • 举报
回复
高手啊。。。。
Rockey723 2013-10-15
  • 打赏
  • 举报
回复
牛逼啊牛逼,好牛逼
赵4老师 2013-10-14
  • 打赏
  • 举报
回复
使用命令重定向操作符可以使用重定向操作符将命令输入和输出数据流从默认位置重定
向到不同的位置。输入或输出数据流的位置即为句柄。

下表将列出可用的句柄。

句柄      句柄的数字代号 描述
STDIN     0              键盘输入
STDOUT    1              输出到命令提示符窗口
STDERR    2              错误输出到命令提示符窗口
UNDEFINED 3-9            这些句柄由应用程序单独定义,并且是各个工具特定的。

数字 0 到 9 代表前 10 个句柄。可以使用命令 Cmd.exe 运行程序并将该程序前 10 个
句柄中的任何一个重定向。要指定想使用的句柄,可在重定向操作符前面键入该句柄的
数字。如果未定义句柄,则默认的 < 重定向输入操作符是 0,而默认的 > 重定向输出
操作符是 1。键入 > 或 < 操作符之后,必须指定要读取或写入数据的位置。可以指定
文件名或另一个现有的句柄。

要指定重定向到现有句柄,请使用与 (&) 字符,后面接要重定向的句柄号
(例如 &句柄#)。例如,下面的命令可以将句柄 2(即 STDERR)重定向到
句柄 1(即 STDOUT):

2>&1

下表列出了可用于将输入和输出数据流进行重定向的操作符。

重定向操作符 描述
> 将命令输出写入到文件或设备(例如打印机)中,而不是写在命令提示符窗口或句柄中。
< 从文件中而不是从键盘或句柄中读入命令输入。
>> 将命令输出添加到文件末尾而不删除文件中的信息。
>& 将一个句柄的输出写入到另一个句柄的输入中。
<& 从一个句柄读取输入并将其写入到另一个句柄输出中。
| 从一个命令中读取输出并将其写入另一个命令的输入中。也称作管道。

默认情况下,可以从键盘将命令输入(即 STDIN 句柄)发送到 Cmd.exe,然后由
Cmd.exe 将命令输出(即 STDOUT 句柄)发送到命令提示符窗口。

重定向输入 (<)
要将键盘输入重定向到文件或设备,请使用 < 操作符。例如,要从 File.txt 获取
sort 命令的输入,请键入:

sort<file.txt

File.txt 的内容将以字母顺序列表的方式显示在命令提示符窗口中。

< 操作符可以打开具有只读访问的指定文件名。所以,不能使用该操作符向文件中写入
信息。例如,如果以 <&2 启动程序,则所有试图读取句柄 0 的操作都将失败,因为句
柄 2 最初是以只写访问打开的。

 注意

0 是 < 重定向输入操作符的默认句柄。
重定向输出 (>)
几乎所有的命令都将输出发送到命令提示符窗口。即使将输出发送到驱动器或打印机的
命令也会在命令提示符窗口显示消息和提示。

要将输出从命令提示符窗口重定向到文件或设备,请使用 > 操作符。可以在许多命令中
使用该操作符。例如,要将 dir 输出重定向到 Dirlist.txt,请键入:

dir>dirlist.txt

如果 Dirlist.txt 不存在,Cmd.exe 将创建该文件。如果 Dirlist.txt 存在,Cmd.exe
将使用 dir 命令的输出替换文件中的信息。

要运行 netsh routing dump 命令,然后将输出发送到 Route.cfg,请键入:

netsh routing dump>c:\route.cfg

> 操作符可以打开具有只写访问属性的指定文件。所以,不能使用该操作符读取文件。
例如,如果使用重定向 >&0 启动程序,则所有试图写入句柄 1 的操作都将失败,因为
句柄 0 最初是以只读访问打开的。

 注意

1 是 > 重定向输出操作符的默认句柄。
复制句柄
重定向操作符 & 可以将输出或输入从一个指定句柄复制到另一个指定的句柄。例如,
要将 dir 输出发送到 File.txt 并将错误输出发送到 File.txt,请键入:

dir>c:\file.txt 2>&1

复制句柄时,可以复制该句柄原状态的所有特性。例如,如果一个句柄具有只写访问的
属性,则该句柄的所有副本都具有只写访问属性。不能将一个具有只读访问属性的句柄
复制到另一个具有只写访问属性的句柄。

使用 & 操作符重定向输入和副本
要将重定向输入操作符 (<) 与复制操作符 (&) 一起使用,指定的文件必须已经存在。
如果输入文件存在,Cmd.exe 将以只读方式打开该文件,然后将文件中包含的字符作为
输入发送到此命令(如同从键盘输入一样)。如果指定了句柄,Cmd.exe 将指定的句柄
复制到系统现有的句柄中。

例如,要以句柄 0 输入读取(即 STDIN)的方式打开 File.txt,请键入:

<file.txt

要打开 File.txt,并在内容排序后将输出发送到命令提示符窗口(即 STDOUT),请键入:

sort<file.txt

要查找 File.txt,然后将句柄 1(即 STDOUT)和句柄 2(即 STDERR)重定向到
Search.txt,请键入:

findfile file.txt>search.txt 2<&1

要以句柄 0 输入读取(即 STDIN)的方式复制用户定义句柄 3,请键入:

<&3

使用 & 操作符重定向输出和复制
如果将输出重定向到文件且指定了现有的文件名,Cmd.exe 将以只写方式打开文件并覆
盖该文件内容。如果指定了句柄,Cmd.exe 将文件复制到现有句柄中。

要将用户定义句柄 3 复制到句柄 1,请键入:

>&3

要将包括句柄 2(即 STDERR)的所有输出从 ipconfig 命令重定向到
句柄 1(即 STDOUT),然后将输出重定向到 Output.log,请键入:

ipconfig.exe>>output.log 2>&1

使用 >> 重定向操作符追加输出
要从命令中将输出添加到文件末尾而不丢失文件中已存在的任何信息,请使用两个连续
的大于号(即 >>)。例如,下面的命令可以将由 dir 命令生成的目录列表追加到
Dirlist.txt 文件:

dir>>dirlist.txt

要将 netstat 命令的输出追加到 Tcpinfo.txt 的末尾,请键入:

netstat>>tcpinfo.txt

使用管道操作符 (|)
管道操作符 (|) 可以提取一个命令的输出(默认情况下是 STDOUT),然后将其导入另
一个命令的输入中(默认情况下是 STDIN)。例如,下面的命令将对目录分类:

dir | sort

在本例中,将同时启动两个命令,但随后 sort 命令会暂停,直到它接收到 dir 命令
的输出为止。sort 命令使用 dir 命令的输出作为输入,然后将输出发送到
句柄 1(即 STDOUT)。

合并带重定向操作符的命令
可以通过合并带有其他命令和文件名的筛选器命令创建自定义命令。例如,可以使用以
下命令存储包含“LOG”字符串的文件名:

dir /b | find "LOG" > loglist.txt

dir 命令的输出通过 find 筛选器命令发送。包含字符串 "LOG" 的文件名作为文件名
列表(例如,NetshConfig.log、Logdat.svd 和 Mylog.bat)存储在文件
Loglist.txt 中。

要在相同命令中使用多个筛选器,请使用管道 (|) 分隔筛选器。例如,下面的命令将
搜索 C 盘上的每个目录以查找包含 "LOG" 字符串的文件名,并且在命令提示符窗口中
每次显示一屏:

dir c:\ /s /b | find "LOG" | more

利用管道 (|) 可以将 Cmd.exe 导向为通过 find 筛选器命令发送 dir 命令输出。
find 命令只选择包含字符串 "LOG" 的文件名。more 命令可以显示由 find 命令选择
的文件名(在命令提示符窗口中每次显示一屏)。有关筛选器命令的详细信息,请参阅
使用筛选器。

chenza123a 2013-10-14
  • 打赏
  • 举报
回复
果断要顶上来
紫月亮5678 2013-10-14
  • 打赏
  • 举报
回复
好haohaohao
891022145 2013-10-14
  • 打赏
  • 举报
回复
jnyinyanlei 2013-10-14
  • 打赏
  • 举报
回复
高人到处是啊
加载更多回复(27)

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧