我有一个制表符分隔的文件,我正试图将其转换为制表符分隔文件。我在用C。我一直在读文件的第二行。现在我只有数以万计的行重复第一行。
#include <stdio.h>
#include <string.h>
#define SELLERCODE A2LQ9QFN82X636
int main ()
{
typedef char* string;
FILE* stream;
FILE* output;
string asin[200];
string sku[15];
string fnsku[15];
int quality = 0;
stream = fopen("c:\out\a.txt", "r");
output = fopen("c:\out\output.txt", "w");
if (stream == NULL)
{
perror("open");
return 0;
}
for(;;)
{
fscanf(stream, "%[^t]t%[^t]", sku, fnsku);
printf("%st%sn", sku, fnsku);
fprintf(output, "%st%st%t%st%st%in", sku, fnsku, asin, quality);
}
}
首选fgets()
读取输入并解析程序中的行,例如使用sscanf()
或strtok()
。
fscanf
是出了名的难以使用
您的fscanf在第一行之后没有执行任何转换
它读取一个TAB之前的字符,然后忽略TAB,并读取更多字符直到下一个TAB。在循环的第二次,sku
没有数据:第一个字符是TAB。
请执行检查返回值。它帮助很大。
chk = fscanf(stream, "%[^t]t%[^t]", sku, fnsku);
/* 2 conversions: sku and fnsku */
if (chk != 2) {
/* something went wrong */
}
您正在使用进行阅读
fscanf(stream, "%[^t]t%[^t]", sku, fnsku);
读取第一行之后,该行应以制表符结束(如"%[^t]t%[^t]"
中所示)。输入缓冲区有最后一个制表符"\t",上面的函数调用没有读取它。因此,在下一次迭代中,它从一开始就用您的格式字符串读取。但下一次迭代中的fcanf
会立即返回,因为它在一开始就遇到了制表符"\t"("%[^t]"
),因此缓冲区仍然具有最后一个读入值。从现在起,每次迭代都尝试使用fscanf
读取文件,但每次在一开始遇到't'
时都会失败。因此,您不会继续读取文件,并且程序缓冲区中的第一个读取值显示在上下
您需要读出终止扫描集匹配的最后一个字符。您可以在fscanf ()
调用后使用fgetc (stream)
,也可以使用以下格式字符串:"%[^t]t%[^t]%*c"
。%*c
是分配抑制语法。这将从输入文件中读取一个字符,但随后将其丢弃
此外,您还应该检查fscanf ()
返回的内容。如果它没有返回2(要读取的元素数),那么就有一个问题需要处理。通过这种方式,您可以确保在一次调用中读取正确数量的元素。
所以你可以做:
while (!feof (stream))
{
fscanf(stream, "%[^t]t%[^t]", sku, fnsku);
fgetc (stream);
printf("%st%sn", sku, fnsku);
fprintf(output, "%st%st%t%st%st%in", sku, fnsku, asin, quality);
}
或者你可以做:
while (!feof (stream))
{
fscanf(stream, "%[^t]t%[^t]%*c", sku, fnsku);
printf("%st%sn", sku, fnsku);
fprintf(output, "%st%st%t%st%st%in", sku, fnsku, asin, quality);
}
但我建议用fgets ()
阅读它,然后用strtok ()
或其他方法在程序中解析它。
第1版:
请注意,如果原始文件以'n'
结尾,那么在如上所述读取行之后,将在缓冲区中添加一个额外的换行符。如果您仍然考虑使用fscanf ()
直接读取字段,其中每行有多个用't'
分隔的字段,并且一个条目以'n'
终止,那么您应该使用以下格式字符串:"%[^t]t%[^t]n"
。
当我们没有得到文件的确切格式时,很难回答。文件是否只包含一行,字段用制表符分隔?或者有多行,每行都有制表符分隔的字段。如果后面的情况是真的,最好是一次扫描整行,然后在内部进行解析。
好的,这是实际发生的事情。你正在阅读第一行,从那时起,你什么都不读,只是重复使用这些值。您应该检查fscanf
的返回值,如果它小于2(将在第一次迭代后),则退出循环。你的fscanf
行应该是这样的:
if( fscanf(stream, "%[^t]t%[^t]n", sku, fnsku) < 2 ) break;
关键是末尾的换行符,它将吃掉输入中的换行符。
你的printf也有一些问题。(格式化字符串的数目不正确。)我把这个留给你。