c - 如何一次读取一行文件并将每一行传递给 C 中的结构体?

标签 c file struct

我正在尝试在 C 中创建两种方法。一种方法打开文件并在每次调用时一次读取一行,另一种方法接受一行并将该行中的某些信息放入结构中。我的结构方法主要工作,但我不知道如何使第一个方法一次只读取一行并通过它。我只是成功地让它用缓冲区一次读取整个文件。我目前的工作如下:

//First method
char * GimmeALine(int FD){

static char buf[BUFFSIZE];

ssize_t nchr = 0;
ssize_t idx = 0;
off_t *offset = 0;
char *p = NULL;
ssize_t *len;

if((nchr = lseek(FD, *offset, SEEK_SET)) !=-1)
  nchr = read(FD, buf, sizeof(buf));
(close(FD));

if(nchr == -1){
    err_sys("File read error");
}

  if(nchr == 0) return NULL;

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

  if(idx == nchr){
    *offset += nchr;

    return NULL;
    }

   *offset += idx +1;
   *len = idx;
   return buf;
}
//Main used for testing
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFSIZE 1024

//Prototypes
char* GimmeALine(int FD);
struct Country *FillAStruct(char * Line);

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

  int file;
  char* line;
  file = open("AllCountries.dat", O_RDONLY);  //Opens the in file
  if(file == -1){
    err_sys("File open error");
  }

   GimmeALine(file);
   close(file);
  return 0;
}

作为作业的一部分,我们需要使用 open()、read() 和 close() 函数,而不是更简单的 f 对应函数。如有任何帮助,我们将不胜感激。

最佳答案

首先,有一些观察结果。 (1) 如果您在函数内静态声明数组,则永远不能从函数返回指向字符数组的指针。为什么?当函数返回时,它的地址空间被破坏 - 这意味着当您从 char * 函数返回时,您的 buf 将不再存在于内存中。 (有几个与此无关的细节和解决方法)。您的主要选择是 (a) 将足够大小的数组作为参数传递给函数,或者 (b) 为函数中的 buf 动态分配空间。我将在下面向您展示 (a)。

接下来,关于您的编码风格...虽然不是错误,但 C 标准风格避免使用 Initial-capscaMelCase 标签(变量名称、结构体)名称等)赞成全部小写。参见例如NASA - C Style Guide, 1994再说一次,这不是一个错误,而是您正在逆流划行的区域......

根据注释,使用read,您只能从文件描述符中读取最多固定个字节数,而不引用各个字符的内容实际上是。 read 将简单地读取可用的内容,最多可达指定的大小。这意味着您可以从用于存储读取内容的 buf 中解析每一行。

这本身并不困难,只需使用指向 buf 的指针并循环,直到找到换行符 或到达最后读取的字符。但是,您确实需要某种方法来跟踪您在文件中的位置,这样您就不会在每次调用读取函数时一遍又一遍地读取相同的第一行。传递一个指向每次调用期间更新的文件offset的指针可以帮助您跟踪您所在的位置。 (将其视为一个结束指针,指向每次连续调用时从文件中读取的下一个字符)

您还需要阅读 read 的手册页,并密切注意可能的各种返回值。除了下面显示的简短子集之外,您还可以利用更多内容。

最后,下面是每次调用函数时使用 open/read 从文本文件读取 'line' 的一种方法的示例。调用电话后如何分配线路由您决定。如果您遇到困难,请告诉我。

#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)

返回“char *”

这里有一个快速更新,将 readline 的返回更改为 char * 以及所需的其他更改。

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

#define BUFSZ 128

char *readline (int fd, char *buf, size_t sz, off_t *offset, size_t *len);

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

    if (argc < 2) return 1;

    int fd = open (argv[1], O_RDONLY);
    if (fd == -1) { 
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return -1;
    }

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

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

    close (fd);

    return 0;
}

/* read 'sz' bytes from file 'fd' beginning at file 'offset'
   storing all chars  in 'buf', where 'buf' is terminated at
   the first newline found. On success, returns pointer to 
   buf, otherwise NULL on error or EOF with 0 chars read.
*/
char *readline (int fd, char *buf, size_t sz, off_t *offset, size_t *len)
{
    ssize_t nchr = 0;
    ssize_t idx = 0;
    char *p = NULL;

    /* set file position indicator */
    if ((lseek (fd, *offset, SEEK_SET)) == -1) {    /* lseek error   */
        fprintf (stderr, "%s() error: seek failure (FD '%d').\n",
                __func__, fd);
        return NULL;
    }

    /* read 'sz' bytes from 'fd' */
    if ((nchr = read (fd, buf, sz)) == -1) {   /* read error   */
        fprintf (stderr, "%s() error: read failure (FD '%d').\n",
                __func__, fd);
        return NULL;
    }

    /* end of file - no chars read */
    if (nchr == 0) return NULL;

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

    if (idx == nchr) {  /* newline not found  */
        *offset += nchr;
        *len = nchr;
        *buf = 0;       /* set buf as empty-string for return */

        return NULL;
    }

    *len = idx;         /* set length   */
    *offset += idx + 1; /* set offset   */

    return buf;
}

关于c - 如何一次读取一行文件并将每一行传递给 C 中的结构体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32621781/

相关文章:

C base64编码字符串

jquery - Blueimp 文件上传插件在 Windows 客户端浏览器上速度较慢

file - Lua:更新文件十六进制编辑器样式的部分

c - 将 strcmp 与数组一起使用

C/C++ Windows 10 x64 (17763) 企业 DACL 问题

c++ - 为什么编译需要这么长时间?

c - 一次读取一行字符

java - 从 java 读取 PDF 文件时关闭它

c++ - 函数返回结构指针

c - 结构中的数组和结构的 Malloc