说这是我想要阅读的文件:
07983988 REMOVE String1
13333337 ADD String4 100
34398111 TRANSFER String5 String6 100
这是唯一有效的3种格式。
我正在使用以下代码块来检查解析的行的格式:
// Read from file.
while (!feof(fd)) {
// Check for format.
if (fscanf(fd, "%d %s %s %s %lf", ×tamp, transaction_type_str, company1, company2, &value)) {
node_t *transaction = create_node((long int)timestamp, 1, company1, company2, value);
add_node(transactions, transaction);
} else if (fscanf(fd, "%d %s %s", ×tamp, transaction_type_str, company1)) {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, 0);
add_node(transactions, transaction);
} else if (fscanf(fd, "%d %s %s %lf", ×tamp, transaction_type_str, company1, &value)) {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, value);
add_node(transactions, transaction);
}
然而,这给了我一个无限循环。我是C的I / O新手,我想知道使用标记化方法或基于行的格式搜索方法是否更好。
答案 0 :(得分:1)
概述:
char buffer[4096];
while (fgets(buffer, sizeof(buffer), fd) != 0)
{
int offset;
if (sscanf(buffer, "%d %s %n", ×tamp, transaction_type_str, &offset) == 2)
{
char *residue = buffer + offset;
if (strcmp(transaction_type_str, "REMOVE") == 0)
{
if (sscanf(residue, "%s", company1) == 1)
…process remove…
else
…report error, etc…
}
else if (strcmp(transaction_type_str, "ADD") == 0)
{
if (sscanf(residue, "%s %lf", company1, &value) == 2)
…process add…
else
…report error, etc…
}
else if (strcmp(transaction_type_str, "TRANSFER") == 0)
{
if (sscanf(residue, "%s %s %lf", company1, company2, &value) == 3)
…process transfer…
else
…report error, etc…
}
else
{
…report error and continue or break…
}
}
}
您可以使分析更加严格,例如,坚持在辅助sscanf()
呼叫完成后没有未使用的数据,等等。这很费劲,但远非不可能。
这涵盖了所请求的代码 - 它在分析行的其余部分之前识别请求的事务类型。
答案 1 :(得分:0)
问题在于您使用feof测试作为while控件。以下是它无法正常工作的原因。
Why is “while ( !feof (file) )” always wrong?
FAQ > Why it's bad to use feof() to control a loop
该函数测试文件结束指示符,而不是流本身。 这意味着另一个功能实际上负责设置 已达到表示EOF的指标。这通常是 由执行读取EOF的函数完成。我们可以 按照该功能的问题,我们发现大多数读取 函数将在读完所有数据后设置EOF,然后 执行了最终读取,导致没有数据,只有EOF。
考虑到这一点,它如何表现为我们的错误 代码片段?简单......当程序通过循环得到 最后一行数据,fgets()正常工作,没有设置EOF, 我们打印出数据。循环返回到顶部和调用 to feof()返回FALSE,我们再次开始循环。 这一次,fgets()看到并设置了EOF,但感谢我们的穷人 逻辑,我们继续处理缓冲区,却没有意识到这一点 它的内容现在是未定义的(很可能是从最后一个未触及的 循环)。
答案 2 :(得分:0)
使用fgets()
然后sscanf()
与" %n"
说明符一起检测扫描完成情况。
通过检测扫描是否到达终点并且没有其他文本在线,我们有一个清晰,对称的解析检测。很像OP的原始代码。
#define BUFSIZE 200
char buf[BUFSIZE];
while (fgets(buf, sizeof buf, fd) != NULL) {
int n = 0;
if (sscanf(buf, "%d %s %s %s %lf %n",
×tamp, transaction_type_str, company1, company2, &value, &n));
if (n > 0 && buf[n] == '\0') {
node_t *transaction = create_node((long int)timestamp, 1, company1, company2, value);
add_node(transactions, transaction);
continue;
}
n = 0;
sscanf(buf, "%d %s %s %n",
×tamp, transaction_type_str, company1, &n));
if (n > 0 && buf[n] == '\0') {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, 0);
add_node(transactions, transaction);
continue;
}
n = 0;
sscanf(buf, "%d %s %s %lf %n",
×tamp, transaction_type_str, company1, &value, &n);
if (n > 0 && buf[n] == '\0') {
node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, value);
add_node(transactions, transaction);
continue;
}
Handle_BadLine(buf); // do not use transaction_type_str, company1, company2, value, n
}
注意:使用"%s"
是危险的。最好限制宽度
char transaction_type_str[20];
...
sscanf(buf, "%d %19s ...