麻烦从.text文件获取信息并将其放入C中的.csv文件中

时间:2014-12-17 00:24:11

标签: c

这是一个学校项目,我遇到了一些困难。我在Visual Studio 2012工作。我是C的新手,所以提前抱歉。

Project Over View

从文本文件(Manhattan_temp_data.txt)获取数据并将其写入.csv文件(TemperatureData.csv)。最终目标是制作一张电子表格,可用于在曼哈顿创建1年温度数据的直观表示。

我的文本文件如下(正好是366行)

Year    Month    Day Mean 
1896    5   1    61.5
1896    5   2    63
1896    5   3    64.5 
1896    5   4    -99   <The -99 means no collected data> 

我的.csv文件如下所示

Year \t Month \t Day \t Mean \t Interpolated Mean

这是我的代码

#include <stdio.h> 
#include <string.h> 
#include <math.h> 
#include <stdlib.h> 
#include <conio.h> 

//Structure for my Text file read
typedef struct TempTXTData{ 
    int Year; 
    int Month; 
    int Day; 
    double Mean; 
} TempTXTData_t; 

int main ()
{

FILE *FPT; //Represents My Text File 
FILE *FPC; //Represents My .csv File
int i; 
TempTXTData_t TempData[366]; 

//Where I open both my text and .csv files 
FPT= fopen("Manhattan_temp_data.txt", "r"); 
  if( FPT == NULL )
   {
      printf("Load Failure Press any key to exit...\n");
      exit(EXIT_FAILURE);
   }
FPC= fopen("TemperatureData.csv", "w");
 if( FPC == NULL ) 
   {
      fclose(FPT);
      printf("Load Failure Press any key to exit...\n");
      exit(EXIT_FAILURE);
   }
 //Function where I take data from my .txt file and input it into my .csv file
 for(i=1; i<366 && fscanf(FPT, "%f %f %f %f", &TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean) !=4; i++) 
{
    for (i=1; i<366; i++) 
        fprintf(FPC, "%f, %f, %f, %f \n",&TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean);
 }


//Closing Files 
fclose(FPT); 
fclose(FPC); 

getch(); 
return 0;  
}

问题

当我运行代码时,我得到并打开我的Excel表格,我的所有行和列都是相同的。前三列均为0,而最后一列为-9.3E + 61。

我的猜测是我没有从我的.txt文件中获取数据,这让我相信我在这行中有错误...

 for(i=0; i<366 && fscanf(FPT, "%f %f %f %f", &TempData[i].Year, &TempData[i].Month,    &TempData[i].Day, &TempData[i].Mean) !=4; i++) 

感谢你的时间,

Alex

3 个答案:

答案 0 :(得分:3)

现在还有一些事情,但没有解决方案(现在无法进行测试):

  • C数组从0索引到size - 1(您实际上使用<运算符),因此您的循环应该从0迭代。您要么避免使用评论文本,在这种情况下,您应该将起始索引保留为1并存储在TempData[i-1] otherwize中,将索引更改为0
  • 您的年/月/日数据类型没有理由不是int
  • 电子表格在这里没有见解。首先,您应该查看CSV文件。可能需要配置一些东西才能正确解析数据。
  • 最后,由于您因此而收到错误,您的输入文件Manhattan_temp_data.txt应该只读(r)。
  • Bonus one,我知道你们windows的人必须放一些C函数来避免关闭终端,但你至少应该使用更标准的函数,比如getchar()。不会为您带来太多成本,也会在其他操作系统上进行编译。

希望这会对您有所帮助,或至少编辑您的帖子以适应实际问题。

答案 1 :(得分:2)

您需要在格式字符串末尾添加换行符

fprintf(FPC, "%f \t %f \t %f \t %f \t\n",&TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean);
                                  /*  ^ this character is newline.

由于您的YearMonthDayint,您必须使用%d说明符

fprintf(FPC, "%d \t %d \t %d \t %f \t\n",&TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean);

你没有将字段的地址传递给fprintf,而是将字段删除&

fprintf(FPC, "%d \t %d \t %d \t %f \t\n", TempData[i].Year, TempData[i].Month, TempData[i].Day, TempData[i].Mean);

并提出一个建议,检查fscanf是否准确读取了您希望在案例中阅读的参数数量更改

fscanf(FPT, "%f \t %f \t %f \t %f \t", &TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean) !=EOF

到这个

fscanf(FPT, "%d \t %d \t %d \t %f \t\n", &TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean) != 4

因为fscanf从Linux手册页

返回成功匹配的项目数

此外,您的fscanf将因文件的第一行而失败,因此不会更新停留在文件开头的流指针,因此您必须阅读整行并使用sscanf否则你将无法跳过第一行并继续阅读,而你的代码将在第一行中止读取,你将得到一个空文件。

RETURN VALUE
   These  functions  return  the  number  of  input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early
   matching failure.

   The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs.  EOF is also returned if a  read
   error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.

还有一件事,你的格式字符串可能是

"%d\t%d\t%d\t%f\n"

您不需要额外的空格和最后一个\t字符。

这段代码应该这样做

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

//Structure for my Text file read
typedef struct TempTXTData{
    int Year;
    int Month;
    int Day;
    double Mean;
} TempTXTData_t;

int main ()
{
    FILE *FPT; //Represents My Text File
    FILE *FPC; //Represents My .csv File
    int i;
    int done;
    TempTXTData_t TempData[366];

    //Where I open both my text and .csv files
    //FPT= fopen("Manhattan_temp_data.txt", "r");
    FPT = fopen("data.dat", "r");
    if (FPT == NULL)
    {
        printf("Load Failure Press any key to exit...\n");
        exit(EXIT_FAILURE);
    }

    FPC= fopen("TemperatureData.csv", "w");
    if( FPC == NULL )
    {
        fclose(FPT);
        printf("Load Failure Press any key to exit...\n");
        exit(EXIT_FAILURE);
    }

    done = 0;
    for (i = 1 ; (i < 366) && (done == 0) ;  i++)
    {
        char  buffer[1024];
        char *pointer;
        /* using fgets is better as was mentioned in other answers */
        pointer = fgets(buffer, sizeof(buffer), FPT);
        if (pointer != NULL)
        {
            int matched;
            matched = sscanf(pointer, "%d%d%d%lf", &(TempData[i].Year), &(TempData[i].Month), &(TempData[i].Day), &(TempData[i].Mean));
            if (matched == 4)
                fprintf(FPC, "%d,%d,%d,%f\n", TempData[i].Year, TempData[i].Month, TempData[i].Day, TempData[i].Mean);
        }
        else
            done = 1;
    }


    //Closing Files
    fclose(FPT);
    fclose(FPC);

    return 0;
}

答案 2 :(得分:2)

您编辑了可能会破坏以前答案的问题,这不是一个好的策略。

由于您已将年,月,日元素更改为int(来自double),因此您必须更改scanf()printf()字符串。 scanf()的其中一个问题是,%f用于读取float值,而%lf用于读取double值,但printf()使用%f {1}}用于打印两者(因为float值在函数调用期间转换为double

你不要跳过文件的标题行;这是一个问题。

如果是我,我一次使用fgets()读取一行,然后扫描用sscanf()读取的行。这使我可以更轻松地检测错误格式的数据。

好像很奇怪,你处理的年数只有128天;我遇到的大部分都有365或366(问题现在已经解决了!)。

不要对{EOF}进行fscanf()测试;测试&#39;给了我正确数量的值&#39;。

C中的数组从索引0开始。

您的代码嵌套输入和输出循环;这是轻微的灾难,因为您为第一行读取打印366个结果值,然后为下一行读取另外366个结果值,依此类推。请注意,大多数值未定义;他们不需要是零或任何有用的东西。您只想在阅读完所有内容后进行打印(特别是在插入缺失值时)。你不想打印地址。你确实想要打印换行符。

enum { MAX_DAYS_PER_YEAR = 366 };

char line[4096];

/* Skip header line */
if (fgets(line, sizeof(line), FPT) == 0)
{
    fputs("Empty file!\n", stderr);
    exit(1);
}

/* Read up to 366 input lines */
for (i = 0; i < MAX_DAYS_PER_YEAR; i++)
{
    if (fscanf(FPT, "%d %d %d %lf", &TempData[i].Year, &TempData[i].Month,
               &TempData[i].Day, &TempData[i].Mean) != 4)
        break;
}

/* Print only the lines that were read */
for (j = 0; j < i; j++) 
    fprintf(FPC, "%d\t%d\t%d\t%.2f\n", TempData[i].Year, TempData[i].Month,
            TempData[i].Day, TempData[i].Mean);

这会生成制表符分隔的数据(TSV文件),但通常将此类文件称为CSV文件,即使C明显不准确。 (DSV for&#39;分隔符分隔值&#39;对于此类文件来说是一个准确但罕见的术语。输出文件是带有制表符分隔符的DSV,与带有逗号分隔符的DSV形成对比。)