这是一个学校项目,我遇到了一些困难。我在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
答案 0 :(得分:3)
现在还有一些事情,但没有解决方案(现在无法进行测试):
0
索引到size - 1
(您实际上使用<
运算符),因此您的循环应该从0
迭代。您要么避免使用评论文本,在这种情况下,您应该将起始索引保留为1
并存储在TempData[i-1]
otherwize中,将索引更改为0
。int
。Manhattan_temp_data.txt
应该只读(r
)。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.
由于您的Year
,Month
和Day
为int
,您必须使用%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形成对比。)