You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C语言高效打印文件中行号数组指定的内容?

高效打印文件中指定行号的方法

先看你提供的原始代码(这里有个明显问题:size=1但你访问了lineSeekArray[1],这会触发数组越界,属于未定义行为,得先修正这个问题):

const int size = 1; 
int lineSeekArray[size]; 
lineSeekArray[0] = 0; 
lineSeekArray[1] = 1; // 此处越界,size为1时索引仅能到0
static const char filename[] = "testfile.txt"; 
FILE *file = fopen ( filename, "r" ); 
int i =0; 
if ( file != NULL ) { 
    char line [ 328 ]; /* 或其他合适的最大行长度 */ 
    while ( fgets ( line, sizeof line, file ) != NULL ) {/* 读取一行 */ 
        i++; 
        if(i == 9) { 
            fputs ( line, stdout ); /* 输出该行 */ 
        } 
    } 
    fclose ( file ); 
}

你的需求是:根据用户输入的动态大小行号数组,打印数组中指定的行(比如数组包含0和1时打印这两行)。下面是两种高效的实现思路:


方案一:排序行号数组,顺序遍历匹配(推荐)

这种方法适配绝大多数场景,逻辑简单且性能优异:

  1. 先对目标行号数组做升序排序,这样我们可以按顺序遍历文件,匹配到目标行后就推进数组指针,直到所有目标都匹配完成,还能提前终止遍历。
  2. 遍历文件时,每读取一行就检查当前行号是否在目标数组中,匹配到就打印,同时标记该目标已完成。

优化后的代码示例:

#include <stdio.h>
#include <stdlib.h>

// qsort所需的整数比较函数
int compareInts(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    // 示例:用户输入的动态目标行号(这里假设要打印第0、1、5、9行)
    int targetLines[] = {9, 0, 1, 5};
    int targetCount = sizeof(targetLines) / sizeof(targetLines[0]);
    
    // 排序目标行号,方便顺序匹配
    qsort(targetLines, targetCount, sizeof(int), compareInts);
    
    static const char filename[] = "testfile.txt";
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror("文件打开失败");
        return 1;
    }
    
    char line[328];
    int currentLine = 0; // 注意:如果你的行号从1开始计数,这里初始值改成1
    int targetIndex = 0;
    
    // 遍历文件,直到读完或所有目标行都匹配完成
    while (fgets(line, sizeof(line), file) != NULL && targetIndex < targetCount) {
        if (currentLine == targetLines[targetIndex]) {
            fputs(line, stdout);
            targetIndex++; // 匹配到一个目标,推进到下一个
        }
        currentLine++;
    }
    
    fclose(file);
    return 0;
}

为什么这个方案高效?

  • 仅需遍历文件一次,无需反复打开或跳转。
  • 排序后可提前终止遍历(所有目标匹配完成后直接退出循环),避免不必要的读取操作。
  • 时间复杂度由文件读取(O(N),N为文件总行数)和排序(O(M log M),M为目标行数量)组成,在绝大多数场景下都足够高效。

方案二:预存行偏移量(适合多次查询场景)

如果需要多次查询不同的行号,可以先把文件每一行的起始字节偏移量存储起来,之后直接用fseek跳转读取:

#include <stdio.h>
#include <stdlib.h>

int main() {
    static const char filename[] = "testfile.txt";
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror("文件打开失败");
        return 1;
    }
    
    // 先遍历文件,记录每一行的起始偏移量
    long long *lineOffsets = NULL;
    int lineCount = 0;
    long long currentOffset = ftell(file);
    
    char line[328];
    while (fgets(line, sizeof(line), file) != NULL) {
        // 动态扩容偏移量数组
        long long *temp = realloc(lineOffsets, (lineCount + 1) * sizeof(long long));
        if (!temp) {
            perror("内存分配失败");
            free(lineOffsets);
            fclose(file);
            return 1;
        }
        lineOffsets = temp;
        lineOffsets[lineCount] = currentOffset;
        lineCount++;
        currentOffset = ftell(file);
    }
    
    // 示例:用户输入的目标行号
    int targetLines[] = {0, 1, 9};
    int targetCount = sizeof(targetLines) / sizeof(targetLines[0]);
    
    // 跳转读取目标行
    for (int i = 0; i < targetCount; i++) {
        int lineNum = targetLines[i];
        if (lineNum < 0 || lineNum >= lineCount) {
            printf("行号%d不存在\n", lineNum);
            continue;
        }
        fseek(file, lineOffsets[lineNum], SEEK_SET);
        fgets(line, sizeof(line), file);
        fputs(line, stdout);
    }
    
    free(lineOffsets);
    fclose(file);
    return 0;
}

注意事项:

  • 该方案适合多次重复查询的场景,第一次遍历存储偏移量的开销可以被后续查询分摊。
  • 文本文件的换行符(Windows是\r\n,Linux是\n)不影响ftell记录的字节偏移,所以跳转读取是可靠的。
  • 如果文件极大(比如几十GB),存储所有行偏移量会占用较多内存,此时方案一更合适。

额外提醒

  1. 行号计数一致性:你的原始代码中i从0开始,i++后判断i==9,实际打印的是第9行(行号从1开始)还是第10行?一定要明确行号的计数起点,避免逻辑错误。
  2. 动态数组处理:如果用户输入的行号数量是动态的,要用malloc或realloc分配数组,不能用固定大小的数组。
  3. 边界检查:要判断目标行号是否在文件的有效行号范围内,避免越界访问。

内容的提问来源于stack exchange,提问作者Samun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:48:01