C - 使用 lseek 向后移动文件中的指针
C - moving back the pointer in the file using lseek
我正在用 C 编写一个学术项目,我只能使用 <fcntl.h>
和 <unistd.h>
库来进行文件操作。
我有逐行读取文件的功能。算法是:
- 在文件开头设置指针并获取当前位置。
- 以恒定大小将数据读取到缓冲区 (
char buf[100]
),逐个字符迭代并检测行尾 '\n'
。
- 增加当前位置:
curr_pos = curr_pos + length_of_read_line;
- 使用
lseek(fd, current_position, SEEK_SET);
将指针设置为当前位置
SEEK_SET
- 将指针设置为距文件开头的给定偏移量。在我的伪代码中 current_position
是偏移量。
实际上它工作正常,但我总是将指针从文件的开头开始 - 我使用 SEEK_SET - 它没有优化。
lseek
也接受参数 SEEK_CUR
- 这是当前位置。如何从指针的当前位置向后移动指针 (SEEK_CUR)。我尝试设置负偏移量,但没有用。
从文件中读取数据行的最有效方法通常是读取可能跨越多行的大块数据,处理块中的数据行直到到达末尾,将任何部分行从缓冲区结束到开始,然后读取另一块数据。根据目标系统和要执行的任务,最好读取足够的内容以填充部分行之后剩余的 space ,或者始终读取字节数的二次幂和使缓冲区足够大以容纳该大小的块加上最大长度的部分行(上次读取遗留下来的)。这种方法的一个困难是所有数据都使用同一个缓冲区从流中读取。然而,在可行的情况下,它通常比使用对 fread
的许多单独调用具有更好的性能,并且可能比使用 fgets
.
更好。
虽然标准库函数应该可以促进行输入,但 fgets
的设计是相当不必要的敌意,因为它没有提供读取数据量的方便指示。读取每一行后,想要包含可打印部分的字符串的代码将不得不使用 strlen
来尝试确定读取了多少数据(希望输入不包含任何零字节),然后检查之前的字节尾随零以查看它是否是换行符。不是不可能,但至少很尴尬。如果 fread-and-buffer 方法将满足应用程序的需求,它可能至少与使用 fgets
一样有效,如果不是更高的话,并且因为稳健地使用 fgets()
所需的努力将是可比的对于需要使用缓冲方法的情况,不妨使用后者。
由于您的问题被标记为 posix, I would go with getline()
,无需手动移动文件指针。
示例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE* fp;
char* line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("input.txt", "r");
if(fp == NULL)
return -1;
while((read = getline(&line, &len, fp)) != -1)
{
printf("Read line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if(line)
free(line);
return 0;
}
带有自定义输入的输出:
Read line of length 11:
first line
Read line of length 12:
second line
Read line of length 11:
third line
我正在用 C 编写一个学术项目,我只能使用 <fcntl.h>
和 <unistd.h>
库来进行文件操作。
我有逐行读取文件的功能。算法是:
- 在文件开头设置指针并获取当前位置。
- 以恒定大小将数据读取到缓冲区 (
char buf[100]
),逐个字符迭代并检测行尾'\n'
。 - 增加当前位置:
curr_pos = curr_pos + length_of_read_line;
- 使用
lseek(fd, current_position, SEEK_SET);
将指针设置为当前位置
SEEK_SET
- 将指针设置为距文件开头的给定偏移量。在我的伪代码中 current_position
是偏移量。
实际上它工作正常,但我总是将指针从文件的开头开始 - 我使用 SEEK_SET - 它没有优化。
lseek
也接受参数 SEEK_CUR
- 这是当前位置。如何从指针的当前位置向后移动指针 (SEEK_CUR)。我尝试设置负偏移量,但没有用。
从文件中读取数据行的最有效方法通常是读取可能跨越多行的大块数据,处理块中的数据行直到到达末尾,将任何部分行从缓冲区结束到开始,然后读取另一块数据。根据目标系统和要执行的任务,最好读取足够的内容以填充部分行之后剩余的 space ,或者始终读取字节数的二次幂和使缓冲区足够大以容纳该大小的块加上最大长度的部分行(上次读取遗留下来的)。这种方法的一个困难是所有数据都使用同一个缓冲区从流中读取。然而,在可行的情况下,它通常比使用对 fread
的许多单独调用具有更好的性能,并且可能比使用 fgets
.
虽然标准库函数应该可以促进行输入,但 fgets
的设计是相当不必要的敌意,因为它没有提供读取数据量的方便指示。读取每一行后,想要包含可打印部分的字符串的代码将不得不使用 strlen
来尝试确定读取了多少数据(希望输入不包含任何零字节),然后检查之前的字节尾随零以查看它是否是换行符。不是不可能,但至少很尴尬。如果 fread-and-buffer 方法将满足应用程序的需求,它可能至少与使用 fgets
一样有效,如果不是更高的话,并且因为稳健地使用 fgets()
所需的努力将是可比的对于需要使用缓冲方法的情况,不妨使用后者。
由于您的问题被标记为 posix, I would go with getline()
,无需手动移动文件指针。
示例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE* fp;
char* line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("input.txt", "r");
if(fp == NULL)
return -1;
while((read = getline(&line, &len, fp)) != -1)
{
printf("Read line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if(line)
free(line);
return 0;
}
带有自定义输入的输出:
Read line of length 11:
first line
Read line of length 12:
second line
Read line of length 11:
third line