这是一个学校项目,我遇到了很多困难。我在Visual Studio 2012工作。我对C很陌生,所以提前抱歉。
项目视图
从文本文件(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++)
谢谢你的时间,
亚历克斯
事情很少,但还没有解决方案(现在无法测试(:
- C 数组从
0
到size - 1
进行索引(您实际上使用<
运算符执行此操作(,因此您的循环应该从0
迭代。要么你想避免注释文本,在这种情况下,你应该保留开始索引1
并存储在TempData[i-1]
其他,将索引更改为0
。 - 没有理由不
int
年/月/日的数据类型。 - 电子表格在这里是没有插曲的。首先,您应该查看CSV文件。可能需要为 excel 配置一些内容以正确解析数据。
- 最后,由于您因此收到错误,因此您的输入文件
Manhattan_temp_data.txt
应以只读方式打开(r
(。 - 奖励一,我知道你们Windows的人必须放置一些C函数以避免关闭终端,但你至少应该使用更标准的函数,例如
getchar()
。对您来说成本不高,也可以在其他操作系统上编译。
希望这会对您有所帮助,或者至少编辑您的帖子以适应实际问题。
您需要以这种方式在格式字符串的末尾添加一个换行符
fprintf(FPC, "%f t %f t %f t %f tn",&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 tn",&TempData[i].Year, &TempData[i].Month, &TempData[i].Day, &TempData[i].Mean);
而且您不会将字段的地址传递给fprintf
而是字段删除&
fprintf(FPC, "%d t %d t %d t %f tn", 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 tn", &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.
还有一件事,您的格式字符串可能是
"%dt%dt%dt%fn"
您不需要额外的空格和最后一个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,%fn", TempData[i].Year, TempData[i].Month, TempData[i].Day, TempData[i].Mean);
}
else
done = 1;
}
//Closing Files
fclose(FPT);
fclose(FPC);
return 0;
}
您编辑的问题可能会破坏以前的答案,这不是一个好的策略。
由于您将年,月,日元素更改为int
(从double
(,因此您必须更改scanf()
和printf()
字符串。 scanf()
的一个问题是%f
用于读取float
值,%lf
用于读取double
值,但printf()
使用%f
来打印两者(因为float
值在函数调用期间转换为double
(。
您不会跳过文件的标题行;这是一个问题。
如果是我,我会使用fgets()
一次读取一行,然后扫描用sscanf()
读取的行。 这使我能够更轻松地检测格式不正确的数据。
奇怪的是,你正在处理的年份只有128天;我遇到的大多数年份都有365或366天(这个问题现在已经解决了!(。
不要测试 EOF fscanf()
;测试"给了我正确的值数"。
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, "%dt%dt%dt%.2fn", TempData[i].Year, TempData[i].Month,
TempData[i].Day, TempData[i].Mean);
这将生成制表符分隔的数据(TSV 文件(,但通常将此类文件称为 CSV 文件,即使 C 明显不准确。 (DSV 表示"分隔符分隔值"是此类文件的准确但罕见的术语。 输出文件是带有制表符分隔符的 DSV,而不是带有逗号分隔符的 DSV。