0

我有一个程序,它获取两条路径作为命令行参数。第一个参数(实际上是第二个,因为第一个是命令名本身)是程序读取的文件(输入文件)的路径。第二个是程序写入的文件(输出文件)的路径。

int main(int argc, char *argv[])
{
    int num;
    /*if there are too many arguments print an error message*/
    if(argc > 3)
    {
        perror("too many arguments");
        return EXIT_FAILURE;
    }
    /*if there is at least one argument use it as path to input file*/
    if(argc > 1)
        if (!freopen(argv[1], "r", stdin)) {
            perror("Path of input file is Invalid");
            return EXIT_FAILURE;
        }
    /*if there are two arguments use the second one as output*/
    if(argc == 3)
        if (!freopen(argv[2], "w", stdout))
        {
            perror("Path of output file is Invalid");
            return EXIT_FAILURE;
        }
/*more code....*/
}
/*(compiled to run file "dtoa.out")*/

该程序工作正常:如果提供了有效的输入和路径输出路径,它将从文件中读取和写入,如果提供的参数太多或输入文件的路径无效,程序将打印一条错误消息并退出。

问题是提供无效的输出文件路径时:

$./dtoa ./tests/ExistingInput1.txt ./tests/NonExistingOutput.txt

在这种情况下,程序只会创建丢失的输出文件,而不是返回NULL并打印错误消息,这是不受欢迎的行为。我该如何更改它,以便在找不到文件时,该方法将返回NULL而不是创建新文件?

4

4 回答 4

2

模式技巧(在问题的"r+"评论中给出)可能就足够了,但也stdout可供阅读。
(这是个问题吗?)

而不是使用freopen()你可以使用open()没有O_CREAT标志。
然后可以将获得的文件描述符替换为标准输出dup2()
http://man7.org/linux/man-pages/man2/open.2.html
http://man7.org/linux/man-pages/man2/dup.2.html

这是一个最小的例子。

$ rm -f output.txt
$ ./prog_c output.txt
before
after
$ touch output.txt
$ ./prog_c output.txt
before
$ cat output.txt 
after
$ 

源代码:


/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

// for printf()
#include<stdio.h>

// for open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if defined _MSC_VER // compiling with visual-studio
# include <io.h>
#endif

// for dup2() and close()
#include <unistd.h>

int
main(int argc,
     char **argv)
{
  printf("before\n");
  fflush(stdout); // in case something is pending in buffer...
  if(argc>1)
  {
#if defined _MSC_VER // compiling with visual-studio
    int fd=_open(argv[1], _O_WRONLY|_O_TRUNC); // no _O_CREAT
#else
    int fd=open(argv[1], O_WRONLY|O_TRUNC); // no O_CREAT
#endif
    if(fd!=-1)
    {
      dup2(fd, STDOUT_FILENO);
      close(fd);
    }
  }
  printf("after\n");
  return 0;
}
于 2020-03-29T13:53:16.587 回答
1

这是记录在案的行为。如果文件不存在,则创建它。

于 2020-03-29T13:28:35.823 回答
1

问题是当提供无效的输出文件路径时 [...] 程序只会创建丢失的输出文件而不是返回NULL

w这是使用模式(或任何其他基于w或的模式)打开文件的记录行为a。如果这不是您想要的——并且您应该考虑是否确实如此——那么您需要使用不同的模式,至少在最初是这样。根据您的要求,如果文件不存在,所有r模式都会导致fopen()和失败。freopen其中一些以允许读写的方式打开文件,例如,

    if (argc == 3) {
        if (!freopen(argv[2], "r+", stdout)) {
            perror("Path of output file is Invalid");
            return EXIT_FAILURE;
        }
    }

如果您想确保stdout' 的模式不允许写入,和/或如果您想确保目标文件被截断,即使没有写入任何内容,那么您可以重新打开它两次,首先是在基于读取的模式下并且,如果成功,则在只写模式下:

    if (argc == 3) {
        if (!freopen(argv[2], "r+", stdout)) {
            perror("freopen (output)");
            return EXIT_FAILURE;
        }
        if (!freopen(NULL, "w", stdout)) {
            perror("freopen (output)");
            return EXIT_FAILURE;
        }
    }
于 2020-03-29T14:27:15.383 回答
0

尝试使用模式'r'的fopen并检查文件指针是否为NULL,这样你就可以知道文件是否存在。例子:

char path[256];
scanf("%s", path);
FILE* fp = NULL;

fp = fopen(path, "r");
if (!fp)
{
    printf("The file doesen't exist!");
}
于 2020-03-29T13:31:51.627 回答