c - 使用系统调用在 C moSTLy 中逐行读取文件

标签 c

我正在尝试逐行读取和解析文件。 我只想使用简单的系统调用(readopenclose、...)而不是 fgetsgetc 因为我希望以某种方式学习基础知识。 (我看了一些关于类似问题的答案,但他们都使用 fgets 等)。

这是我目前所拥有的:我编写的一个函数,它将 1024 个字符存储在文件的缓冲区中。

int main(void) {
    const char *filename = "file.txt";
    int fd = open(filename, O_RDONLY);
    char *buffer = malloc(sizeof (char) * 1024); 

    read(fd, buffer, 1024);        
    printf("%s", buffer);
    close(fd);
    free(buffer);    
}

例如,如何在 '\n' 处停下来? 我知道一旦我知道在哪里停止,我就可以使用具有正确偏移量的 lseek 继续读取我停止的文件。

我不希望将整个文件存储在我的缓冲区中然后再对其进行解析。 我想在我的缓冲区中添加一行,然后解析该行并重新分配我的缓冲区并继续读取文件。

我在想这样的事情,但我觉得它优化得不好,并且不确定之后在哪里添加 lseek:

char *line = malloc(sizeof (char) * 1024);
read(fd, buffer, 1);
int i = 0;
    while(*buffer != '\n' && *buffer != '\0'){
        line[i] = *buffer;
        ++i;
        *buffer++;
        read(fd, buffer, 1); //Assuming i < 1024 and *buffer != NULL
    }


  /* lseek somewhere after, probably should make 2 for loops 
   ** One loop till file isn't completly read
   ** Another loop inside that checks if the end of the line is reached
   ** At the end of second loop lseek to where we left
   */

谢谢:)

编辑:说明标题。

最佳答案

如果您要使用read 一次读取一行(fgetsgetline 的目的),您在找到每个 '\n' 后,必须跟踪文件中的偏移量。然后只需一次读取一行,在当前行之后的 offset 处开始下一个read

我理解希望能够使用低级函数以及 fgetsgetline。您会发现,您基本上最终会重新编码(以一种效率较低的方式)已经在 fgetsgetline 中完成的工作。但这当然是很好的学习。这是一个简短的例子:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BUFSZ 128

ssize_t readline (char *buf, size_t sz, char *fn, off_t *offset);

int main (int argc, char **argv) {

    if (argc < 2) return 1;

    char line[BUFSZ] = {0};
    off_t offset = 0;
    ssize_t len = 0;
    size_t i = 0;

    /* using open/read, read each line in file into 'line' */
    while ((len = readline (line, BUFSZ, argv[1], &offset)) != -1)
        printf (" line[%2zu] : %s (%zd chars)\n", i++, line, len);

    return 0;
}

/* read 'sz' bytes from file 'fn' beginning at file 'offset'
   storing all chars  in 'buf', where 'buf' is terminated at
   the first newline found. On success, returns number of
   characters read, -1 on error or EOF with 0 chars read.
 */
ssize_t readline (char *buf, size_t sz, char *fn, off_t *offset)
{
    int fd = open (fn, O_RDONLY);
    if (fd == -1) {
        fprintf (stderr, "%s() error: file open failed '%s'.\n",
                __func__, fn);
        return -1;
    }

    ssize_t nchr = 0;
    ssize_t idx = 0;
    char *p = NULL;

    /* position fd & read line */
    if ((nchr = lseek (fd, *offset, SEEK_SET)) != -1)
        nchr = read (fd, buf, sz);
    close (fd);

    if (nchr == -1) {   /* read error   */
        fprintf (stderr, "%s() error: read failure in '%s'.\n",
                __func__, fn);
        return nchr;
    }

    /* end of file - no chars read
    (not an error, but return -1 )*/
    if (nchr == 0) return -1;

    p = buf;    /* check each chacr */
    while (idx < nchr && *p != '\n') p++, idx++;
    *p = 0;

    if (idx == nchr) {  /* newline not found  */
        *offset += nchr;

        /* check file missing newline at end */
        return nchr < (ssize_t)sz ? nchr : 0;
    }

    *offset += idx + 1;

    return idx;
}

示例输入

除了第二个在每行文本之间包含一个空行之外,以下数据文件是相同的。

$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

$ cat dat/captnjack2.txt
This is a tale

Of Captain Jack Sparrow

A Pirate So Brave

On the Seven Seas.

输出

$ ./bin/readfile dat/captnjack.txt
 line[ 0] : This is a tale (14 chars)
 line[ 1] : Of Captain Jack Sparrow (23 chars)
 line[ 2] : A Pirate So Brave (17 chars)
 line[ 3] : On the Seven Seas. (18 chars)

$ ./bin/readfile dat/captnjack2.txt
 line[ 0] : This is a tale (14 chars)
 line[ 1] :  (0 chars)
 line[ 2] : Of Captain Jack Sparrow (23 chars)
 line[ 3] :  (0 chars)
 line[ 4] : A Pirate So Brave (17 chars)
 line[ 5] :  (0 chars)
 line[ 6] : On the Seven Seas. (18 chars)

关于c - 使用系统调用在 C moSTLy 中逐行读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33106505/

相关文章:

c - C 中的十六进制

c - 为什么ioctl返回 "bad address"

c - Scanf 语句被忽略

c - 如何检查或更改 USLT (ID3) 中的编码?

c++ - 此 OpenMP 代码使 linux 崩溃

c++ - 使用 getchar() 和 -O3 的奇怪行为

c++ - 如何访问计算机的 RAM 和 ROM 的所有字节?

从 Unity3D 构建的 Android .apk 在设备上出现 'App not installed' 错误

c - 使用 Memory BIO 直接读/写握手数据

c - 让我确保我理解 C pthread 互斥体