我知道这是一个之前被问过的问题,但看到它没有真正得到答案,而且我还没能找到其他任何地方,我想我会再问它。 / p>
基本上我有一个程序从标准输入传递.txt文件时,它会读取它并用*
替换每个数字字符。现在我想知道是否有办法测试传递给它的文件是否是.txt。这样做是为了确保输出结果实际可用,如果有人要传递.odt或.doc它不起作用,我只是试图阻止该步骤发生。
if( file is a .txt file)
{
run program
}
else
{
print error message and exit
}
基本上我正在寻找我应该在if语句中添加的内容。任何和所有的帮助表示赞赏。
答案 0 :(得分:2)
如果您只是寻找.txt
分机,那就不是那么糟糕了。验证传递的文件名是4个字符或更长(如果不是,它太短而不能使用该扩展名),然后执行strcmp
(或stricmp
以允许*.TXT
,*.tXT
等等,因为Windows在文件名的最后四个字符和".txt"
之间不区分大小写。注意:在Windows上,有一个PathFindExtension
函数可以帮助您找到文件扩展名的开头。
如果你试图验证内容是文本,这是一个更难的问题。这完全取决于你对“文本”的意思。没有单一的方式来表示文字;您通常可以通过在文件开头检查BOM
(Byte Order Mark)来便宜地识别UTF-16 / UTF-32文本(有时是UTF-8文本)。但是ASCII文本没有这样的标记(并且任意二进制数据可能具有重合的BOM);对于ASCII,你会遇到启发式问题,例如:文件< 128
中的所有字节(将字节解释为unsigned char
),可能需要进行额外检查以假设某些ASCII不可打印字符表示“不是真正的文本”。如果它是一个ASCII超集,则所有字节值都是合法的,因此启发式归结为识别语言;这不是一项微不足道的任务。 libmagic
可以在Linux上提供帮助,但在文本方面它仍在进行启发式猜测。
答案 1 :(得分:1)
使用file
的Linux popen
可以非常接近。 (当然,如果你正在运行Windows,它没有多大帮助)虽然file
在分析每种类型的文件时不是100%防弹,但它在确定文件是否只包含ASCII文本时非常好。使用popen
获取file
的结果并解析输出,您可以确定file
是否认为该文件仅包含ASCII文本。例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#define PMAX 64
int chkinput (int nargs, int nreq, char **args);
int file_exists (char *f);
int main (int argc, char **argv) {
if (chkinput (argc, 2, argv )) return 1; /* quick input check */
char buf[PMAX] = {0};
char cmd[PMAX] = {0};
FILE *pp = NULL;
/* create cmd string for popen */
snprintf (cmd, PMAX, "%s %s", "file", argv[1]);
/* call Linux 'file' on filename via popen to
test whether the file is a text file */
if ((pp = popen (cmd, "r")))
{
if (fgets (buf, PMAX, pp)) /* optional - strip newline */
{
pclose (pp);
/* if ASCII found in buf - it's text */
if (strstr (buf, "ASCII")) {
printf ("\n %s -- %s\n", argv[1], strchr (buf, 'A'));
}
else /* it's not text -- handle appropriately */
printf ("\n %s -- not ASCII text\n\n", argv[1]);
}
}
return 0;
}
/* quick hack to make sure you provided a valid
filename as the first argument to the program */
int chkinput (int nargs, int nreq, char **args)
{
if (nargs < nreq || !file_exists (args[1])) { /* validate input */
char *p = args[0];
char *prg = p;
while (*p) if (*p++ == '/') prg = p;
fprintf (stderr, "error: invalid input, usage: %s filename"
" (must exist)\n", prg);
return 1;
}
return 0;
}
/* check if file exists */
int file_exists (char *f)
{
errno = 0;
int flags = O_CREAT | O_WRONLY | O_EXCL;
int mode = S_IRUSR | S_IWUSR;
int fd = open (f, flags, mode);
if (fd < 0 && errno == EEXIST)
return 1;
else if (fd) {
close (fd);
unlink (f);
}
return 0;
}
使用/输出
$ ./bin/pipe_chkfile ~/.bashrc
/home/david/.bashrc -- ASCII text
$ ./bin/pipe_chkfile bin/pipe_chkfile
bin/pipe_chkfile -- not ASCII text
$ ./bin/pipe_chkfile ~/Documents/beast-attack.pdf
/home/david/Documents/beast-attack.pdf -- not ASCII text
$ ./bin/pipe_chkfile ~/Documents/nhs-20131009.odt
/home/david/Documents/nhs-20131009.odt -- not ASCII text