【问题标题】:How to avoid bad input/output file name as well bad arguments in a C program如何在 C 程序中避免错误的输入/输出文件名以及错误的参数
【发布时间】:2013-09-21 04:36:17
【问题描述】:

我需要避免错误的输入/输出文件名以及无效的参数。我也使用过类似的东西,但它并没有真正的帮助:

while ((c = getopt(argc, argv, "i:o:")) != -1) {
        switch (c) {


             case 'i':
                      inFile = strdup(optarg);
             break;
             case 'o':
                      outFile = strdup(optarg);
             break;
             default:
                      //usage(argv[0]);
                      break;
    }
}

      if ((ptr1 = fopen(inFile, "r+")) == NULL) {
            fprintf(stderr, "Error: cannot open file %s\n", inFile);
            exit(-1);
    }
    if ((ptr = fopen(outFile, "w+")) == NULL) {
            fprintf(stderr, "Error: cannot open file %s\n", outFile);
            exit(-1);
    }

测试我的程序的python程序如下:

class Arg2(Test):
   name = "arg2"
   description = "bad arguments"
   timeout = 5
   def run(self):
      self.runexe(["fastsort", "a", "b", "c", "d"],
            stderr = usage_error, status = 1)
      self.done()

class Badin(Test):
   name = "badin"
   description = "bad input file"
   timeout = 5
   def run(self):
      invalid = mktemp(prefix='/invalid/path/')
      self.runexe(["fastsort", "-i", invalid, "-o", "outfile"],
          stderr = "Error: Cannot open file {0}\n".format(invalid), status = 1)
      self.done()

class Badout(Test):
   name = "badout"
   description = "bad output file"
   timeout = 5
   def run(self):
      infile = self.project_path + "/infile"
      # create a valid (empty) input file
      open(infile, "a").close()
      invalid = mktemp(prefix='/invalid/path/')
      self.runexe(["fastsort", "-i", infile, "-o", invalid],
          stderr = "Error: Cannot open file {0}\n".format(invalid), status = 1)
      self.done()

您能否给我一些提示和代码 sn-p 避免错误文件名/错误文件路径以及 C 中无效参数处理的常用方法?

【问题讨论】:

  • 在什么方面“没有真正帮助”?错误消息和返回值有什么问题?你想要什么不同? (尽管您可能想要记录 errnostrerror。并且您可能想要返回像 1 这样的正数而不是 -1,因为这可能意味着您已经退出,因为您抓住了叹息。)
  • 另外,什么是“坏文件名”?在大多数平台上,几乎任何字符都可以出现在文件名中——在 POSIX 上,/ 将被解释为路径分隔符而不是文件名的一部分,\000 被解释为文件名的结尾而不是文件名的一部分,但是其他任何事情都会发生,所以没有什么要检查的。一个主要的例外是 Windows。如果您想要特定于 Windows 的错误信息,您可能希望使用 CreateFile 而不是 fopen,但您始终可以打印出 errno 是什么用于 fopen("a\n?*:\003", "w+") 并自己找出来。

标签: python c file error-handling


【解决方案1】:

假设“错误的文件名”和“错误的路径名”是指由于文件名或路径名有问题而无法打开的路径,那么您处理此问题的一般方法是正确的:尝试fopen,事后报告错误,而不是试图猜测它是否会起作用。

您缺少的是检查 errno 是否失败。而不是这个一般错误:

fprintf(stderr, "Error: cannot open file %s\n", inFile);

...使用errnostrerrorperror 打印出特定的内容:

fprintf(stderr, "Error: cannot open file ");
perror(inFile);

然后你会得到类似的东西:

Error: cannot open file foo/bar: No such file or directory.

如果您想以编程方式区分错误,只需检查errno

if (errno == ENOENT) {
    /* The directory, or one of its parents, doesn't exist, so handle that */
} else {
    /* whatever */
}

另一方面,如果您想将信息传递回调用程序,只需返回 errno 作为您的 retcode:

exit(errno)

这不是典型的做法——但exit(-1) 也不是。通常,您使用1 表示“一般故障”,使用-1 表示“我退出,因为我发现了信号1”。


同时,不清楚您所说的“错误文件名”和“错误路径名”是什么意思,但似乎所有这些都算数:

  • 路径的文件名部分太长。 errno 将是 ENAMETOOLONG。
  • 整个路径名太长。 errno 将是 ENAMETOOLONG。
  • 指定的目录或链中指定的父目录之一不存在。 errno 将是 ENOENT
  • 指定的目录或父目录之一不是目录。 errno 将是 ENOTDIR
  • 路径名中的字符无效。在 POSIX 中没有这样的事情,所以这只会发生在像 Windows 这样的非 POSIX 平台上,这些平台通常不会定义调用 C 和 POSIX 函数会返回什么错误。 (如果你真的想处理 Windows 错误,你可能想使用CreateFile 而不是fopen 等)

如果您需要在 Windows 或其他平台上处理最后一种情况,最好的办法是对其进行测试:尝试fopen("a b \\?*:; \n \003", "w+") 看看会得到什么。然后你就会知道在你的代码中放什么了。

【讨论】:

  • 使用 stat 不是比打开文件更好的方法吗?比如说,如果文件已经打开写入,导致 COW...
  • @Dru:大概她真正的程序实际上是要对文件一些事情(否则,称它为fastsort 会有点误导......),她是只是试图为其添加更好的错误处理。尝试打开并处理失败总是比先统计然后假设您可以打开要好。
  • 在 POSIX 路径名中存在这样的无效字符:空字节(即\x00)。尝试在 POSIX 平台上的路径名中嵌入空字节可靠地导致调用 os 模块函数时出现 "TypeError: embedded NUL character" 异常。
  • @CecilCurry 不,NUL 字符在 POSIX 路径名中不是无效的。无法从任何 POSIX API 创建或访问此类文件,因为它们都使用以 NUL 结尾的字符串。但是一个符合 POSIX 的系统,也有使用不同字符串标准的非 POSIX API 可以允许它们。
  • @CecilCurry 当然 CPython 的 os 模块只是在非 Windows 平台上使用 POSIX 和/或 C stdlib 函数,这意味着它必须将字符串转换为以 NUL 结尾的字节,并且没有合理的方法使用中间有 ASCII 或 Unicode NUL 的字符串来做到这一点,因此它会引发TypeError。但该错误来自 Python,而不是来自操作系统。 (而且你显然不会在 C 中得到它,所以你不必担心如何在 OP 的 C 代码中处理它。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
  • 2017-08-02
相关资源
最近更新 更多