检查输入是否是C中的txt文件

时间:2015-09-14 18:09:23

标签: c if-statement input

我知道这是一个之前被问过的问题,但看到它没有真正得到答案,而且我还没能找到其他任何地方,我想我会再问它。 / p>

基本上我有一个程序从标准输入传递.txt文件时,它会读取它并用*替换每个数字字符。现在我想知道是否有办法测试传递给它的文件是否是.txt。这样做是为了确保输出结果实际可用,如果有人要传递.odt或.doc它不起作用,我只是试图阻止该步骤发生。

if( file is a .txt file)
{
    run program
}
else
{
    print error message and exit
}

基本上我正在寻找我应该在if语句中添加的内容。任何和所有的帮助表示赞赏。

2 个答案:

答案 0 :(得分:2)

如果您只是寻找.txt分机,那就不是那么糟糕了。验证传递的文件名是4个字符或更长(如果不是,它太短而不能使用该扩展名),然后执行strcmp(或stricmp以允许*.TXT*.tXT等等,因为Windows在文件名的最后四个字符和".txt"之间不区分大小写。注意:在Windows上,有一个PathFindExtension函数可以帮助您找到文件扩展名的开头。

如果你试图验证内容是文本,这是一个更难的问题。这完全取决于你对“文本”的意思。没有单一的方式来表示文字;您通常可以通过在文件开头检查BOMByte 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