C和C++中的逐行阅读是什么意思?

5

我想在C或C++中逐行读取文件,当我假设一行有固定的大小时,我知道如何做到这一点,但是是否有一种简单的方法来计算或获取每行或整个文件所需的确切大小?(如果有人能够逐字读取直到换行符,那也对我有好处。)


4
C语言和C++语言是完全不同的编程语言,它们提供完全不同的解决方案。 - Marlon
5
我喜欢早上闻到家庭作业的味道。 - pcantin
根本问题在于文本行是一个可变长度的记录。它以换行符结束。由于在文本开始之前没有提供大小,因此无法通过读取固定数量的字符输入。必须逐个字符地读取,直到找到终止字符为止。这就成为缓冲区溢出的基础(不知道要预先分配多少内存)。 - Thomas Matthews
7个回答

7
如果您使用流读取器,则所有这些内容都将对您隐藏。请参见getline。以下示例基于此处的代码。
// getline with strings
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main () {
  string str;
  ifstream ifs("data.txt");
  getline (ifs,str);
  cout << "first line of the file is " << str << ".\n";
}

2
cin 可以完全被文件流替换;无论如何,cin 都可以从文件重定向。 - Jonathan Leffler

4
在C语言中,如果你有POSIX 2008库(例如更高版本的Linux),你可以使用POSIX getline()函数。如果你的库中没有这个函数,你可以很容易地实现它,这可能比发明自己的接口更好。
在C++中,你可以使用std::getline()
尽管这两个函数具有相同的基本名称,但调用约定和语义是相当不同的(因为C语言和C++语言是非常不同的)- 当然,它们都读取文件流中的一行数据。
没有一种简单的方法来确定一个文件中最长的行有多长 - 除了读取整个文件以找出,这有点浪费。

3
我会使用IFStream并使用getline从文件中读取内容。 http://www.cplusplus.com/doc/tutorial/files/
int main () {
    string line;
    ifstream myfile ("example.txt");
    if (myfile.is_open())
    {
        while ( myfile.good() )
        {
            getline (myfile,line);
            cout << line << endl;
        }
        myfile.close();
    }
    else cout << "Unable to open file"; 

    return 0;
}

3
问题在于尝试使用getline函数可能会将文件状态设置为不良状态,因此您需要在依赖于line变量内容之前进行检查。例如,流的EOF标志直到在文件末尾尝试读取后才被设置。我建议使用 while (getline(stream, line)) { ... },然后如果您关心的话,可以在循环外检查终止的原因... - Tony Delroy
OP,指的是C或C++。我的答案是用C++编写的,因此它回答了这个问题。@Tony,我同意你的看法。 - Stealth Rabbi

1

在读取完一行之前,您无法获得该行的长度。但是,您可以重复地读入缓冲区,直到达到行末。

对于使用C语言编程,请尝试使用fgets来读取一行代码。它将读取n个字符或遇到换行符停止。您可以读取一个大小为n的小缓冲区,直到字符串中的最后一个字符是换行符。

有关更多信息,请参见上面的链接。

以下是使用小缓冲区读取并显示文件的整行的示例:

#include <stdio.h>
#include <string.h>

int main()
{
   FILE * pFile;

   const int n = 5;
   char mystring [n];
   int lineLength = 0;

   pFile = fopen ("myfile.txt" , "r");
   if (pFile == NULL) 
   {
       perror ("Error opening file");
   }
   else 
   {

        do 
        {
            fgets (mystring , n , pFile);
            puts (mystring);    
                    lineLength += strlen(mystring); 
        } while(mystring[strlen ( mystring)-1] != '\n' && !feof(pFile));

       fclose (pFile);
   }

   printf("Line Length: %d\n", lineLength);
   return 0;
}

1
这不是问题中的“我知道如何在假定某个固定行大小时执行该操作”的部分吗? - Jonathan Leffler
不,只需进行一些修改,您就可以做更多的事情。如果您知道行的确切大小,请将字符串的长度设置为该大小+1。如果您知道行的最大大小,请将字符串的长度设置为max + 1。但是,如果您完全不知道,请在读取周围编写一个循环,并测试读取的最后一个字符是否为行结束符。 - Steve
1
如果您不检查feof(pFile),就有可能陷入无限循环。 - Marlon
我已经在网上搜索了大约一个小时,寻找一种简单的方法来做这件事,这是我遇到的第一个易于理解且有效的解决方案。+1 - reggaeguitar
请注意,fgets() 的结果在未检查是否成功读取一行的情况下被使用。另外,请注意 puts() 在每次调用后输出一个换行符 — 因此它将长输入行分割成多个单独的输出行。 - Jonathan Leffler
显示剩余2条评论

0
在C++中,您可以使用std::getline函数,它接受一个流并读取到第一个'\n'字符。在C语言中,我会使用fgets函数,并不断重新分配缓冲区,直到最后一个字符是'\n',然后我们就知道已经读取了整行。 C++:
std::ifstream file("myfile.txt");
std::string line;
std::getline(file, line);
std::cout << line;

C:

// I didn't test this code I just made it off the top of my head.
FILE* file = fopen("myfile.txt", "r");
size_t cap = 256;
size_t len = 0;
char* line = malloc(cap);

for (;;) {
    fgets(&line[len], cap - len, file);
    len = strlen(line);
    if (line[len-1] != '\n' && !feof(file)) {
        cap <<= 1;
        line = realloc(line, cap);
    } else {
        break;
    }
}

printf("%s", line);

0

getline 只是 POSIX 标准,这里提供一个 ANSI 标准的实现(不需要最大行大小信息!):

const char* getline(FILE *f,char **r)
{
  char t[100];
  if( feof(f) )
    return 0;
  **r=0;
  while( fgets(t,100,f) )
  {
    char *p=strchr(t,'\n');
    if( p )
    {
      *p=0;
      if( (p=strchr(t,'\r')) ) *p=0;
      *r=realloc(*r,strlen(*r)+1+strlen(t));
      strcat(*r,t);
      return *r;
    }
    else
    {
      if( (p=strchr(t,'\r')) ) *p=0;
      *r=realloc(*r,strlen(*r)+1+strlen(t));
      strcat(*r,t);
    }
  }
  return feof(f)?(**r?*r:0):*r;
}

现在,在你的主程序中,这变得简单而且短小:

  char *line,*buffer = malloc(100);
  FILE *f=fopen("yourfile.txt","rb");
  if( !f ) return;
  setvbuf(f,0,_IOLBF,4096);
  while( (line=getline(f,&buffer)) )
    puts(line);
  fclose(f);
  free(buffer);

它可以在Windows上运行,适用于Windows和Unix文本文件, 它可以在Unix上运行,适用于Unix和Windows文本文件


0
这是一种使用std算法和迭代器读取行的C++方法:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>

struct getline :
  public std::iterator<std::input_iterator_tag, std::string>
{
    std::istream* in;
    std::string line;
    getline(std::istream& in) : in(&in) {
        ++*this;
    }
    getline() : in(0) {
    }
    getline& operator++() {
        if(in && !std::getline(*in, line)) in = 0;
    }
    std::string operator*() const {
        return line;
    }
    bool operator!=(const getline& rhs) const {
        return !in != !rhs.in;
    }
};

int main() {
    std::vector<std::string> v;
    std::copy(getline(std::cin), getline(), std::back_inserter(v));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接