【问题标题】:One file to another file conversion in CC中一个文件到另一个文件的转换
【发布时间】:2021-12-16 11:40:58
【问题描述】:

我有一个名为 datafile.data 的输入文件,如下所示:

1,2,1,1,0
1,3,1,1,0
1,1,2,2,1
2,1,2,2,1
2,3,2,3,1
1,1,2,3,2
3,1,1,4,2
2,1,3,2,2
3,3,3,1,2
2,2,3,4,2

这里的第 4 列代表 4 个属性值,例如 A1、A2、A3、A4。最后一列代表类值。对于这个特定的示例文件,有 4 个属性,但对于其他一些文件,可以有“n”个属性,但对于每个文件,最后一列将给出类值。

现在我想将此文件转换为另一个名为:outputfile.exp的文件

输出文件的第一行如下所示:

<Number of rows in the .data file> <Number of attributes> <Max value of A1> <Max value of A2> <Max value of A3> <Max value of A4> <(Max value of last column)+1>

并且输出文件的其余行将与数据文件相同,只有一个变化,即最后一列的每个值都将增加1。

例如,上述示例的输出文件如下所示:

10 4 3 3 3 4 3
1,2,1,1,1
1,3,1,1,1
1,1,2,2,2
2,1,2,2,2
2,3,2,3,2
1,1,2,3,3
3,1,1,4,3
2,1,3,2,3
3,3,3,1,3
2,2,3,4,3

其中第一行的 10 是行数,4 是存在的属性数,(3,3,3,4) 这 4 是属性 A1,A2,A3 和 A4 的最大值,最后 3 代表最高等级价值+1。最后一列的 each 值也增加了 1。

下面我附上我的尝试:

#include <stdio.h>
#include <string.h>
#define MAX_FILE_NAME 100
  
int main()
{
    FILE *fp;
    int count = 0;  // Line counter (result)
    char filename[MAX_FILE_NAME], dataToBeRead[50];
    char c;  // To store a character read from file
  
    // Open the file
    fp = fopen("datafile.data", "r");
  
    // Check if file exists
    if (fp == NULL)
    {
        printf("Could not open file %s", filename);
        return 0;
    }
  
    // Extract characters from file and store in character c
    for (c = getc(fp); c != EOF; c = getc(fp))
        if (c == '\n') // Increment count if this character is newline
            count = count + 1;
  
    fclose(fp);
    
    printf("%d\n",count);
    
    fp = fopen("datafile.data", "r");
    
    if ( fp == NULL )
    {
        printf( "Failed to open." ) ;
    }
    else
    {
        while( fgets ( dataToBeRead, 50, fp ) != NULL )
        {
            printf( "%s" , dataToBeRead ) ;
        }
        fclose(fp) ;
    }
  
    return 0;
}

我得到以下输出:

10
1,2,1,1,1
1,3,1,1,1
1,1,2,2,2
2,1,2,2,2
2,3,2,3,2
1,1,2,3,3
3,1,1,4,3
2,1,3,2,3
3,3,3,1,3
2,2,3,4,3

现在我无法继续进行,因为我对 C 非常陌生,请帮助我。

编辑1:示例的输出格式为:

10 4 3 3 3 4 3
1 2 1 1 1
1 3 1 1 1
1 1 2 2 2
2 1 2 2 2
2 3 2 3 2
1 1 2 3 3
3 1 1 4 3
2 1 3 2 3
3 3 3 1 3
2 2 3 4 3

【问题讨论】:

  • 如果可以将元数据放在文件的末尾会容易很多。如果您想在开始时编写它,则需要读取两次数据或将其全部存储。
  • 我需要在开头写它以匹配特定的模式。所以我不能把它放在最后。
  • 您只需要数据,还是正在寻找在 C 中执行此操作的学习练习?您可能需要认真考虑在文件末尾写入元数据,然后编写另一个程序将该行移到开头。让事情尽可能简单。
  • 老实说我需要这个,因为我正在使用基于规则的分类器,所以我需要将此输入转换为通用输出格式。格式看起来与我在问题中所说的完全相似。所以我需要输出文件顶部的这些数据。我只想将 .data 文件作为命令行参数,它将生成该格式的输出文件。

标签: c file io


【解决方案1】:

您真的不想这样做,因为倒带输入流是一种反模式。但是你可以这样做:

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

FILE * xfopen(const char *path, const char *mode);
void * xmalloc(size_t s);

void
parse_line(const char *buf, int *max, int column_count)
{
    for(int i = 0; i < column_count; i++ ){
        char *end;
        int t = strtol(buf, &end, 10);
        if( t > max[i] ){
            max[i] = t;
        }
        if( !((i < column_count - 1 && *end == ',')
            || (i == column_count - 1 && *end == '\n'))
        ){
            fprintf(stderr, "invalid input '%c' in %s", *end, buf);
            exit(1);
        }
        buf = end + 1;
    }
}


int
main(int argc, char **argv)
{
    const char *path = argc > 1 ? argv[1] : "stdin";
    FILE *in = argc > 1 ? xfopen(path, "r") : stdin;
    char buf[1024];
    int column_count = 1;
    int row_count = 1;
    int *max;

    /* Read first line to determine number of columns */
    if( fgets(buf, sizeof buf, in) == NULL ){
        fputs("Input error\n", stderr);
        return 1;
    }

    for( const char *p = buf; *p; p++ ){
        if( *p == ',' ){
            column_count += 1;
        }
    }
    max = xmalloc(column_count * sizeof *max);
    for( int i = 0; i < column_count; i++ ){
        max[i] = INT_MIN;
    }
    parse_line(buf, max, column_count);
    while( fgets(buf, sizeof buf, in) != NULL ){
        row_count += 1;
        parse_line(buf, max, column_count);
    }
    if( fseek(in, 0L, SEEK_SET) ){
        perror(path);
        return 1;
    }
    printf("%d %d ", row_count, column_count - 1);
    for( int i = 0; i < column_count - 1; i += 1 ){
        printf("%d ", max[i]);
    }
    printf("%d\n", max[column_count - 1] + 1);

    while( fgets(buf, sizeof buf, in) != NULL ){
        char *comma = strrchr(buf, ',');
        if( comma == NULL ){
            fprintf(stderr, "Invalid input\n");
            return 1;
        }
        *comma = '\0';
        int k = strtol(comma + 1, NULL, 10);
        printf("%s,%d\n", buf, k + 1);
    }
}

FILE *
xfopen(const char *path, const char *mode)
{
    FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
        *mode == 'r' ? stdin : stdout;
    if( fp == NULL ){
        perror(path);
        exit(EXIT_FAILURE);
    }
    return fp;
}

void *
xmalloc(size_t s)
{
    void *rv = malloc(s);
    if( rv == NULL ){
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    return rv;
}

您可以将其作为./a.out &lt; datafile.data &gt; outputfile.exp./a.out datafile.data &gt; outputfile.exp 执行,但如果您尝试从管道读取,这将不起作用seek 将失败)。 seek 失败以及无法将其作为过滤器运行,这使其成为次优方法,但将整个文件存储在内存中也有缺点。

【讨论】:

  • 非常感谢。这工作得很好。我只需要稍作修改,实际上在那个输出文件中,属性值和类值不会用逗号分隔,而是用空格分隔。我的意思是根据我上面的例子,输出文件的第二行看起来像:1 2 1 1 1
  • @Dev 提供的示例输出在第一行显示空格作为分隔符。问题中应该包含这样的细节。
  • No no 第一行完全没问题@William,您的代码完全符合我在问题中提出的要求。实际上,这是我的一个小错误。我应该稍微更新一下这个问题吗?我已经尝试相应地修改您的代码并在一定程度上取得了成功。我是否应该编辑问题并再次提供示例输出以及我的尝试?我觉得需要做一些小改动。
  • 可能不需要更新问题。在输出中用空格替换逗号是一个非常简单的修改。
  • 我尝试了多种方法,其中一种方法是我尝试在我写的 main 中修改代码的最后一个 printf 语句:“printf("%s %d\n" , buf, k + 1);" .使用这个我得到输出文件的第二行:1,2,1,1 1 ...但我无法找到如何删除所有逗号并用单个空格填充它们的解决方案。我正在更新问题中的输出文件格式。请帮助我。
【解决方案2】:

由于 William Pursell 在 C 语言中提供了极好的答案,这里有一个 awk 替代方案,尽管 awk 没有标记。

awk -F, -v OFS="," '                            # assign input/output field separator to a comma
    NR==FNR {                                   # this block is invoked for the 1st read of the input file
        for (i = 1; i <= NF; i++) {             # loop over the filelds
            if (max[i] == "" || max[i] < $i) max[i] = $i
                                                # update the max values
        }
        nr = NR; nf = NF                        # store #records and #fields
        next                                    # skip following statements
    }
    FNR==1 {                                    # this block is invoked just before reading he 1st line for the 2nd read of the input file
        printf("%d %d ", nr, nf - 1)            # print #records and #fields - 1
        max[nf]++                               # increment the max value of the last field
        for (i = 1; i <= nf; i++) {             # print max values
            printf("%d%s", max[i], i==nf ? "\n" : " ");
        }
    }
    {                                           # this block is invoked for the 2nd read
        $nf++                                   # increment the value of the last field
        print                                   # print fields as csv
    }
' datafile.data datafile.data                   # read the input file twice

【讨论】:

    【解决方案3】:

    下面是修改后的代码,我想先读取 .names 文件,然后检查 .names 的最后一行是否为零,然后我想生成输出。

    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    FILE * xfopen(const char *path, const char *mode);
    void * xmalloc(size_t s);
    
    void parse_line(const char *buf, int *max, int column_count)
    {
        for(int i = 0; i < column_count; i++ ){
            char *end;
            int t = strtol(buf, &end, 10);
            
            if( t > max[i] ){
                max[i] = t;
            }
            
            if( !((i < column_count - 1 && *end == ',') || (i == column_count - 1 && *end == '\n')) ){
                fprintf(stderr, "invalid input '%c' in %s", *end, buf);
                exit(1);
            }
            buf = end + 1;
        }
    }
    
    int main(int argc, char **argv)
    {
    
        char *path1;
        char *path = argc > 1 ? argv[1] : "stdin";
        
        sprintf(path, "%s.data", argv[1]);
        
        FILE *in = argc > 1 ? xfopen(path, "r") : stdin;
        
        char buf[1024];
        int column_count = 1;
        int row_count = 1;
        int *max;
    
        /* Read first line to determine number of columns */
        if( fgets(buf, sizeof buf, in) == NULL ){
            fputs("Input error\n", stderr);
            return 1;
        }
    
        for( const char *p = buf; *p; p++ ){
            if( *p == ',' ){
                column_count += 1;
            }
        }
        
        max = xmalloc(column_count * sizeof *max);
        
        for( int i = 0; i < column_count; i++ ){
            max[i] = INT_MIN;
        }
        
        parse_line(buf, max, column_count);
        while( fgets(buf, sizeof buf, in) != NULL ){
            row_count += 1;
            parse_line(buf, max, column_count);
        }
        
        if( fseek(in, 0L, SEEK_SET) ){
            perror(path);
            return 1;
        }
        
        printf("%d %d ", row_count, column_count - 1);
        
        for( int i = 0; i < column_count - 1; i += 1 ){
            printf("%d ", max[i]);
        }
        
        printf("%d\n", max[column_count - 1] + 1);
    
        while( fgets(buf, sizeof buf, in) != NULL ){
            char *comma = strrchr(buf, ',');
            if( comma == NULL ){
                fprintf(stderr, "Invalid input\n");
                return 1;
            }
            
            *comma = '\0';
            int k = strtol(comma + 1, NULL, 10);
            for(char *p = buf; *p;  p++){
                if( *p == ',' ) *p = ' '; 
            }
            printf("%s %d\n", buf, k + 1);
        }
    }
    
    FILE *
    xfopen(const char *path, const char *mode)
    {
        FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
            *mode == 'r' ? stdin : stdout;
        if( fp == NULL ){
            perror(path);
            exit(EXIT_FAILURE);
        }
        
        return fp;
    }
    
    void *
    xmalloc(size_t s)
    {
        void *rv = malloc(s);
        if( rv == NULL ){
            perror("malloc");
            exit(EXIT_FAILURE);
        }
        return rv;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-05
      • 2015-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-22
      • 1970-01-01
      • 1970-01-01
      • 2019-03-06
      相关资源
      最近更新 更多