【问题标题】:fopen failing on variable filepathfopen 在变量文件路径上失败
【发布时间】:2019-10-12 22:23:39
【问题描述】:

这个函数被传递了一个文本文件的路径(mapper_path),它包含了每一行其他文本文件的路径。我应该打开 mapper_path.txt 文件,然后打开并评估其中的每个路径(输出中的示例)。 fopen 在 mapper_path 文件上成功,但在它包含的路径上失败。 在失败的情况下,它会打印出我试图打开的确切路径。 我在 Windows 上使用 C 语言并在 Ubuntu 子系统上运行命令。

如何正确读取子路径并将其存储到变量中以打开它?

根据 Rici 的建议解决了!

int processText(char * mapper_path, tuple * letters[])
{
    char line[LINE_SIZE];
    char txt_path[MAX_PATH];

    FILE * mapper_fp = fopen(mapper_path, "r");
    if(!mapper_fp)
    {
       printf("Failed to open mapper path: %s \n", mapper_path);
       return -1;
    }
      //!!! PROBLEM IS HERE !!!
    while(fgets(txt_path, MAX_PATH, mapper_fp))
    {
       //remove newline character from end
       txt_path[strlen(txt_path)-1] = 0;

       //open each txt file path, return -1 if it fails
       FILE* fp = fopen(txt_path, "r");
       if(!fp)
       {
          printf("Failed to open file path:%s\n", txt_path);
          return -1;
       } 
       //...more unimportant code

打印: 无法打开文件路径: /mnt/c/users/adam/documents/csci_4061/projects/blackbeards/testtext.txt 这是我要打开的文件的确切路径。

【问题讨论】:

  • 这种情况一般发生在文件路径不存在,或者你没有打开文件的权限

标签: c string fopen filepath


【解决方案1】:

我怀疑问题与此有关:

我在 Windows 上使用 C 语言并在 Ubuntu 子系统上运行命令。

大概是您使用 Windows 工具创建了 mapper.txt 文件,因此它具有 Windows 行结尾。但是,我认为 Ubuntu 子系统不知道 Windows 行结尾,因此即使您以 'r' 模式打开文件,它也不会将 CR-LF 转换为单个 \n。然后,当您删除输入末尾的 \n 时,您仍然会留下 \r。

当您打印出该行时,\r 将不可见,因为它所做的只是将光标移动到行首并且下一个字符输出是\n。当您打印调试消息时,用其他文本包围字符串通常是一个好主意,因为这可以为您提供有关此类问题的线索。如果您使用过:

printf("Failed to open file path: '%s'\n", txt_path);

您可能已经看到错误:

'ailed to open filepath: '/mnt/c/users/adam/documents/csci_4061/projects/blackbeards/testtext.txt

这里,字符串末尾有\r 的提示是用尾随撇号覆盖消息的第一个字符。


说fgets“将\n 字符添加到[读取的行的末尾]”并不十分准确。更准确地说,如果它存在,它不会删除该字符。行尾很可能没有换行符。例如,该行可能是文本文件中不以换行符结尾的最后一行。或者 fgets 可能已通过达到您提供的字符限制而不是通过找到换行符而终止。

所以你当然最好使用getline 接口,它有两个优点:(a)它为行本身分配存储,所以你不需要提前猜测最大长度,以及(b)它会准确地告诉您它读取了多少个字符,因此您不必计算它们。

使用该信息,您可以删除恰好位于行尾的\n(如果有的话),然后删除前面的\r(如果有的话):

char* line = NULL;
size_t n_line = 0;
for (;;) {
    ssize_t n_read = getline(&line, &n_line, mapper_fp);
    if (n_read < 0) break;  /* EOF or some kind of read error */
    if (n_read > 0 && line[n_read - 1] == '\n') 
        line[nread--] = 0;
    if (n_read > 0 && line[n_read - 1] == '\r') 
        line[nread--] = 0;
    if (nread == 0) continue;  /* blank line */
    /* Handle the line read */
 }
 if (ferr(mapper_fp))
    perror("Error reading mapper file");
 free(line);

【讨论】:

  • 不知道加了\r,谢谢详细解答!我使用了有人建议的 strcspn 函数,它起作用了!
  • @acom:strcspn 解决方案可以工作,但它会扫描整个输入。我的解决方案只检查两个字节,因此效率更高。在这种特殊情况下,额外的效率只是很小的节省,但最好养成在可能的情况下使用非循环(即恒定时间)算法的习惯。
  • 哦,好的,我会尝试实施您的解决方案。我希望尽可能提高效率。谢谢你的建议,我学到了很多!
猜你喜欢
  • 1970-01-01
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-24
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
相关资源
最近更新 更多