【问题标题】:Is it possible to read any particular data directly from a file?是否可以直接从文件中读取任何特定数据?
【发布时间】:2021-10-26 17:23:51
【问题描述】:

是否可以直接从文件中读取任何特定数据而无需逐行或逐字符或逐块读取?

我已将少数学生的姓名、成绩、分数和通过年份存储在档案中。 以下是文件内容..

suraj
1
411
2020
john
3
400
2005
aman raj
5
389
2015

我只想打印学生姓名john 的过去年份。 下面是我的代码..

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    char name[20];
    int roll;
    int total_marks;
    int passing_year;

    FILE *ptr;
    ptr = fopen("/storage/testing.txt", "r");
    if (ptr == NULL)
    {
        perror("File not found");
        exit(-1);
    }

    while (feof(ptr) == 0)
    {
        fgets(name, 20, ptr); // *Edit: The 2nd argument will less or equal to 20. 
        fscanf(ptr, "%d\n", &roll);//line 1
        fscanf(ptr, "%d\n", &total_marks);//line 2
        fscanf(ptr, "%d\n", &passing_year);//line 3

        if (strcmp(name, "john\n") == 0) //\n because fgets() add newline before \0 (only if size specified is more than no. of characters)
            printf("passing year of John was %d\n", passing_year);
    }
    return 0;
}

程序运行成功。下面是控制台的结果..

passing year of John was 2005

[Program finished]

在这里,我只需要passing year of john,但我必须阅读整个文件。当然,我可以通过fseek() 更改指向位置,但我还必须阅读最小的第 1 行、第 2 行和第 3 行。 我想知道,有什么方法可以直接从文件中读取特定数据,就像我们在控制台 I/O(临时存储)中使用变量时使用的那样? 为什么我们不能像控制台一样访问文件中的数据(使用变量)?

【问题讨论】:

  • 评论不用于扩展讨论;这个对话是moved to chat。
  • @BhargavRao 其中许多 cmets 都是对 OP 的提示,甚至是部分答案。我不会称它们为“扩展讨论”,我希望你没有移动它们。

标签: c file pointers


【解决方案1】:

如果每个学生在文件中占用相同的空间(并且该文件可能不再是文本文件),您可以fseek() 到任何特定索引

suraj    |  1 | 411 | 2020\n           // 27 bytes per student
john     |  3 | 400 | 2005\n           // still a text file
aman raj |  5 | 389 | 2015\n           // uses more space than a
pmg      | 42 |  87 | 2000\n           // more efficient format

fseek(studentfile, 27 * 2, SEEK_SET);
fgets(buffer, 28, studentfile); // read aman raj data

【讨论】:

  • 这两个问题都对。您可以为每个学生分配一个编号,然后将fseek 分配给该编号(可能是- 1)。并考虑为大型数据集使用适当的数据库:-)
  • 非常感谢您的回复。我得到了它。再次感谢。
  • 我更喜欢制表符(ASCII 代码 9 或 \t)作为分隔符 - 而不是本示例中的 |。它不会保留有用的字符,例如 |。
  • 实际上,所有|(或制表符)和大多数空格都是多余的,可以在固定宽度格式中省略。它们有助于手动(人工)编辑。
  • @Suraj 如果您需要按名称有效地查找记录(可能根据记录编号),您通常会使用单独的索引。如果该索引已排序(尤其是如果 it 具有固定大小的记录),您可以使用 二分搜索 等技术在其中高效搜索。或者您可以使用哈希表。如果您愿意,该单独的索引可以为您提供主数据库的 fseek 偏移量,这意味着您的主数据库毕竟不必使用固定大小的记录。
【解决方案2】:

[部分,不完整的答案]

使用单独的索引(可能在单独的文件中)来实现对主数据库的高效查找和查找很有用。例如,考虑这个文件:

aman raj   33
john       17
suraj      0

它是按名称的字母顺序排列的,所以理论上你可以在其中使用二分搜索。第二列为您提供了一个数字,您可以将其交给fseek,以直接跳转到您最初在问题中提供的主数据文件中的所需记录(使用fseek 调用,如其他地方所述)。

(虽然您看不到,但我想这个文件中的两列由一个制表符分隔,这样在名称中不会出现任何歧义,例如aman raj。)

或者,这是@pmg 答案中数据文件的索引。在此索引中,第二列中的数字是记录号,而不是原始的 fseek 偏移量。 (即第二列的数字是必须乘以27才能得到pmg代码中fseek偏移的数字。)

aman raj   2
john       1
pmg        3
suraj      0

另一种可能的可能性是哈希表。

【讨论】:

  • 感谢您的回答。
  • 这里的索引有助于识别位置,但它只有在每个学生使用相同的字节时才有效(这里是 27 字节,所以我们使用 index no. * 27 表示fseek()偏移量。)
  • 好的,我用二分搜索试试。
  • @Suraj 澄清一下,索引可以产生需要乘以固定大小记录大小的数字,或者它可以直接将 fseek 偏移量提供到文件中它不使用固定大小的记录。我说明了这两种可能性。
  • 好的,知道了。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2020-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多