【问题标题】:Reading in multiple data files from a mapping file in C从 C 中的映射文件中读取多个数据文件
【发布时间】:2016-01-19 08:53:20
【问题描述】:

首先,我正在创建一个程序,它将读取字符行并查找单词(它们不必具有含义,即 'ab' 可以是 word )并将它们存储在适当的数据结构中。我使用 trie 结构来存储单词。我得到了一个映射文件作为命令行参数,但在映射文件中我有两个需要从中获取信息的数据文件。使用界面如下:first(program name) <mappingfile>.

在映射文件中,存在两个数据文件:<dictFile><dataFile>。我不确定如何读取和存储两个数据文件中提供的信息。到目前为止,我有以下内容:

#include <stdio.h>
#include<stdlib.h>

void readDict(FILE *dict_file){

}

int main(int argc, char *argv[]){
  FILE* file;


  if(argc != 2){ //error in inputing, not 2 files
    printf("error\n");
    return 0;
  }

  file = fopen(argv[1],"r" ); //reading the mapping file

  input;
  if(file == NULL){ //nothing inside file
    printf("file does not exist\n");
    return 0;
  }
}

我的目标是让指针指向映射文件中的相应数据文件,我可以使用它们来读取它们的内容。 我将在命令行中获得以下输入: first(program name) &lt;mappingfile&gt;.

Inisde 映射文件包含两个普通 .txt 文件的行,格式为 &lt;dictFile&gt;&lt;dataFile&gt;.

我希望通过指向相应文件的指针访问&lt;dictFile&gt;&lt;dataFile&gt;.. 的两个内容。

【问题讨论】:

  • 映射文件是指向其他两个文件还是这些文件实际上嵌入到一个文件中?
  • 它们被嵌入到单个映射文件中。在命令行中,您将给出映射文件。在映射文件中,您有 。映射文件中的两个文件都是纯文本文件;
  • 例如:你可以有一个 分别如下: boo22$Book5555bOoKiNg#bOo#TeX123tEXT(JOHN) John1TEXAN4isa1BOoRiSH%whohasa2bo3KING BOOKING bOoKings$12for a TEX-Text(BOOKS (课本)
  • 哦,你的意思是它们实际上是文件名?
  • 好的,如果没有其他人已经给你一个好的答案,我会在有空的时候给你一个答案。

标签: c file pointers command-line-arguments


【解决方案1】:

如果我理解正确,应该这样做。请注意,它假定您的文件名没有任何空格。如果您想使用“非安全”api,您需要将 _CRT_SECURE_NO_WARNINGS 添加到 Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions 下的项目属性中。

#include <stdio.h>
#include<stdlib.h>

void readDict(FILE *dict_file){

}

int main(int argc, char *argv[]){
  FILE* file;


  if(argc != 2){ //error in inputing, not 2 files
    printf("error\n");
    return 1;
  }

  file = fopen(argv[1],"r" ); //reading the mapping file

  //input;
  if(file == NULL){ //nothing inside file
    printf("file does not exist\n");
    return 1;
  }

  char dictFileString[256], dataFileString[256];
  fscanf( file, "%255s %255s", dictFileString, dataFileString );

  FILE *dictFile, *dataFile;
  dictFile = fopen( dictFileString, "r" );
  if (dictFile == NULL) {
      printf( "%s does not exist\n", dictFileString );
      fclose(file);
      return 1;
  }
  dataFile = fopen( dataFileString, "r" );
  if (dataFile == NULL) {
      printf( "%s does not exist\n", dataFileString );
      fclose(file);
      fclose(dictFile);
      return 1;
  }

  readDict(dictFile);

  //  The additional logic would be placed here.

  fclose( dictFile );
  fclose( dataFile );

  //  If you need to read additional file names then loop
  //  back up to read the next line of 'file'

  fclose( file );
  return 0;
}

【讨论】:

  • 这只会读取第一行并且你永远不会关闭你的文件!请不要使用fscanf。读取行是使用fgets 函数完成的。
  • 我的回答是为了展示基本程序。很明显它只会读取第一行。由知道自己需要什么的程序员来完成代码。
  • Linus,这种批评对任何人都没有帮助。它不鼓励他人的帮助。这就是为什么 stackoverflow.com 在互联网上受到如此多的负面评论的原因。请注意,我按要求回答了这个问题,我认为这确实会帮助 Daniel 更上一层楼。
  • OP 在 cmets 中明确表示“您将有 2 列和 x 行,每行遵循以下格式:”,除了您的代码不安全之外,它还受fscanf 溢出错误并泄漏资源。感谢您为 SO 做出的贡献,但我认为这种批评会提高您的回答质量。
  • 似乎有道理,我唯一无法理解的是 char dictFileString[265], dataFileString[256];调用 fscanf 时是否将文件的 txt 保存到两个数组中?
【解决方案2】:

如果我正确理解您的问题,您想解析一个文件,其中每一行包含其他两个文件的 文件名,然后从中读取。您可以使用fgets 逐行读取映射文件。接下来你可以做的是使用函数strtok 将你的字符串拆分为一个空格。我一步一步为你分解。

首先我们要打开映射文件进行读取

if((file = fopen(argv[1],"r")) == NULL) {
  perror("error opening file");
  return 1;
}

这将尝试打开程序命令行参数指定的映射文件,如果失败,它将打印相应的错误消息。

while(fgets(buf, sizeof(buf), file) != NULL) {

打开文件后,我们要遍历所有行,直到到达文件末尾,fgets 将返回 NULL。 fgets 会将当前行放入buf

dictfilename = strtok(buf, " ");
datafilename = strtok(NULL, " ");
strtok(dictfilename, "\n"); /* Remove any trailing newlines */
strtok(datafilename, "\n");

我们需要用分隔符(空格)分割fgets 读取的行,以便我们知道哪个部分对应于字典文件和数据文件。这是通过使用strtok 函数来完成的,该函数返回指向空格之前的子字符串的指针,并且当传入NULL 时,它将返回指向空格之后的子字符串的指针。删除任何尾随换行符的一种稍微奇怪的方法是使用strtok 和换行符作为分隔符。

if((dictfile = fopen(dictfilename,"r")) == NULL) {
  fprintf(stderr, "error opening file %s: %s\n", dictfilename, strerror(errno));
  return 1;
}

if((datafile = fopen(datafilename,"r")) == NULL) {
  fprintf(stderr, "error opening file %s: %s\n", datafilename, strerror(errno));
  return 1;
}

与我们打开映射文件的方式非常相似,我们现在打开fgets 读取的当前行中找到的两个文件,并以“r”模式打开以供读取。如果文件不存在或找不到,则 fopen 调用失败。

printf("Content of %s:\n", dictfilename);
while ((c = getc(dictfile)) != EOF)
  putchar(c);

printf("\nContent of %s:\n", datafilename);
while ((c = getc(datafile)) != EOF)
  putchar(c);

这是“转储”文件内容的一种非常简单的方法。它使用getc 从文件中读取下一个字符并打印它,直到它读取 EOF。这是您应该执行自己的功能的地方。

fclose(dictfile);
fclose(datafile);

之后不要忘记关闭文件,否则会泄漏资源。

最后是我刚才描述的代码

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define MAX_LENGTH 100 // change this to the actual maximum length of your lines.

int main(int argc, char **argv){
  FILE* file, *dictfile, *datafile;
  char c;
  char buf[MAX_LENGTH];
  char *dictfilename, *datafilename;

  if(argc != 2) {
    fprintf(stderr, "Usage: %s <mapping file>\n", argv[0]);
    return 0;
  }

  if((file = fopen(argv[1],"r")) == NULL) {
    perror("error opening file");
    return 1;
  }

  while(fgets(buf, sizeof(buf), file) != NULL) {
    dictfilename = strtok(buf, " ");
    datafilename = strtok(NULL, " ");
    strtok(dictfilename, "\n"); /* Remove any trailing newlines */
    strtok(datafilename, "\n");

    if((dictfile = fopen(dictfilename,"r")) == NULL) {
      fprintf(stderr, "error opening file %s: %s\n", dictfilename, strerror(errno));
      return 1;
    }

    if((datafile = fopen(datafilename,"r")) == NULL) {
      fprintf(stderr, "error opening file %s: %s\n", datafilename, strerror(errno));
      return 1;
    }

    // do something with the files (e.g read all the content)
    printf("Content of %s:\n", dictfilename);
    while ((c = getc(dictfile)) != EOF)
      putchar(c);

    printf("\nContent of %s:\n", datafilename);
    while ((c = getc(datafile)) != EOF)
      putchar(c);
    printf("\n");

    // don't forget to close the files when you're done with them.
    fclose(dictfile);
    fclose(datafile);
  }
  fclose(file);
}

【讨论】:

  • 第二部分数据文件名的 strtok 有问题;我的 *datafile 得到空指针
  • @Dhollasc 您是否使用strtok(datafilename, "\n"); 删除了文件名后的任何换行符?它应该说error opening file,然后是一些关于失败的有用信息。错误信息是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-11
  • 2018-12-28
  • 2011-12-30
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多