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

时间:2015-09-17 02:39:28

标签: 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 个答案:

答案 0 :(得分:0)

首先,有几点意见。 (1)你永远不能从静态声明 函数中的函数返回一个指向字符数组的指针。为什么?当函数返回时,其地址空间被破坏 - 意味着当您从buf函数返回时, char *将不再存在于内存中。 (这里有几个更好的要点和解决方法)。您的主要选择是(a)将足够大的数组作为参数传递给函数,或者(b)为函数中的buf动态分配空间。我将在下面给你(a)。

接下来,关于您的编码风格......虽然不是错误,但C标准样式避免使用Initial-capscaMelCase标签(变量名,结构名称等)来支持全部小写。参见例如NASA - C Style Guide, 1994同样,这不是一个错误,而是一个你在上游​​划分的区域......

在评论之后,使用read,您只能从文件描述符中读取一些fixed个字节,而不会参考单个字符的实际内容。 read只会读取最大可用大小的内容。这意味着您需要解析用于存储所读内容的buf中的每一行。

这本身并不困难,只需使用指针buf并循环,直到找到newline或到达最后一个字符读取。但是,您确实需要一些方法来跟踪文件中的位置,这样您每次调用读取功能时都不会反复阅读相同的第一行。将指针传递给在每次通话期间更新的文件offset可帮助您跟踪自己的位置。 (把它想象成一个结束指针指向每次连续调用时从文件中读取的下一个字符)

您还需要阅读read的手册页,并密切关注可能的各种返回值。您可以使用的内容比下面显示的简短子集要多得多。

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

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

返回&#39; char *&#39;

以下是一项快速更新,可将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;
}