在 C++ 中使用 ifstream 逐行读取文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7868936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Read file line by line using ifstream in C++
提问by lemon
The contents of file.txt are:
file.txt 的内容是:
5 3
6 4
7 1
10 5
11 6
12 3
12 4
Where 5 3
is a coordinate pair.
How do I process this data line by line in C++?
5 3
坐标对在哪里。如何在 C++ 中逐行处理此数据?
I am able to get the first line, but how do I get the next line of the file?
我可以获得第一行,但是如何获得文件的下一行?
ifstream myfile;
myfile.open ("text.txt");
回答by Kerrek SB
First, make an ifstream
:
首先,做一个ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
The two standard methods are:
两种标准方法是:
Assume that every line consists of two numbers and read token by token:
int a, b; while (infile >> a >> b) { // process pair (a,b) }
Line-based parsing, using string streams:
#include <sstream> #include <string> std::string line; while (std::getline(infile, line)) { std::istringstream iss(line); int a, b; if (!(iss >> a >> b)) { break; } // error // process pair (a,b) }
假设每一行由两个数字组成,并逐个令牌读取:
int a, b; while (infile >> a >> b) { // process pair (a,b) }
基于行的解析,使用字符串流:
#include <sstream> #include <string> std::string line; while (std::getline(infile, line)) { std::istringstream iss(line); int a, b; if (!(iss >> a >> b)) { break; } // error // process pair (a,b) }
You shouldn't mix (1) and (2), since the token-based parsing doesn't gobble up newlines, so you may end up with spurious empty lines if you use getline()
after token-based extraction got you to the end of a line already.
你不应该混合 (1) 和 (2),因为基于令牌的解析不会吞噬换行符,所以如果getline()
在基于令牌的提取让你结束之后使用,你可能最终会得到虚假的空行线已经。
回答by K-ballo
Use ifstream
to read data from a file:
用于ifstream
从文件中读取数据:
std::ifstream input( "filename.ext" );
If you really need to read line by line, then do this:
如果您确实需要逐行阅读,请执行以下操作:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
But you probably just need to extract coordinate pairs:
但您可能只需要提取坐标对:
int x, y;
input >> x >> y;
Update:
更新:
In your code you use ofstream myfile;
, however the o
in ofstream
stands for output
. If you want to read from the file (input) use ifstream
. If you want to both read and write use fstream
.
在您使用的代码中ofstream myfile;
,但是o
inofstream
代表output
. 如果要从文件(输入)中读取,请使用ifstream
. 如果您想同时读取和写入使用fstream
.
回答by HugoTeixeira
Reading a file line by line in C++ can be done in some different ways.
在 C++ 中逐行读取文件可以通过一些不同的方式完成。
[Fast] Loop with std::getline()
[快速] 使用 std::getline() 循环
The simplest approach is to open an std::ifstream and loop using std::getline() calls. The code is clean and easy to understand.
最简单的方法是使用 std::getline() 调用打开 std::ifstream 和循环。代码干净且易于理解。
#include <fstream>
std::ifstream file(FILENAME);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
file.close();
}
[Fast] Use Boost's file_description_source
[快速] 使用 Boost 的 file_description_source
Another possibility is to use the Boost library, but the code gets a bit more verbose. The performance is quite similar to the code above (Loop with std::getline()).
另一种可能性是使用 Boost 库,但代码会变得更加冗长。性能与上面的代码非常相似(Loop with std::getline())。
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <fcntl.h>
namespace io = boost::iostreams;
void readLineByLineBoost() {
int fdr = open(FILENAME, O_RDONLY);
if (fdr >= 0) {
io::file_descriptor_source fdDevice(fdr, io::file_descriptor_flags::close_handle);
io::stream <io::file_descriptor_source> in(fdDevice);
if (fdDevice.is_open()) {
std::string line;
while (std::getline(in, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
fdDevice.close();
}
}
}
[Fastest] Use C code
【最快】使用C代码
If performance is critical for your software, you may consider using the C language. This code can be 4-5 times faster than the C++ versions above, see benchmark below
如果性能对您的软件至关重要,您可以考虑使用 C 语言。此代码可以比上面的 C++ 版本快 4-5 倍,请参见下面的基准测试
FILE* fp = fopen(FILENAME, "r");
if (fp == NULL)
exit(EXIT_FAILURE);
char* line = NULL;
size_t len = 0;
while ((getline(&line, &len, fp)) != -1) {
// using printf() in all tests for consistency
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
Benchmark -- Which one is faster?
基准测试——哪个更快?
I have done some performance benchmarks with the code above and the results are interesting. I have tested the code with ASCII files that contain 100,000 lines, 1,000,000 lines and 10,000,000 lines of text. Each line of text contains 10 words in average. The program is compiled with -O3
optimization and its output is forwarded to /dev/null
in order to remove the logging time variable from the measurement. Last, but not least, each piece of code logs each line with the printf()
function for consistency.
我用上面的代码做了一些性能基准测试,结果很有趣。我已经用包含 100,000 行、1,000,000 行和 10,000,000 行文本的 ASCII 文件测试了代码。每行文本平均包含 10 个单词。该程序经过-O3
优化编译,并将其输出转发到/dev/null
以从测量中删除记录时间变量。最后但并非最不重要的一点是,每段代码都使用printf()
函数记录每一行以保持一致性。
The results show the time (in ms) that each piece of code took to read the files.
结果显示了每段代码读取文件所花费的时间(以毫秒为单位)。
The performance difference between the two C++ approaches is minimal and shouldn't make any difference in practice. The performance of the C code is what makes the benchmark impressive and can be a game changer in terms of speed.
两种 C++ 方法之间的性能差异很小,在实践中应该没有任何区别。C 代码的性能使基准测试令人印象深刻,并且可以在速度方面改变游戏规则。
10K lines 100K lines 1000K lines
Loop with std::getline() 105ms 894ms 9773ms
Boost code 106ms 968ms 9561ms
C code 23ms 243ms 2397ms
回答by Martin Broadhurst
Since your coordinates belong together as pairs, why not write a struct for them?
既然你的坐标是成对的,为什么不为它们写一个结构体呢?
struct CoordinatePair
{
int x;
int y;
};
Then you can write an overloaded extraction operator for istreams:
然后你可以为 istreams 编写一个重载的提取操作符:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
And then you can read a file of coordinates straight into a vector like this:
然后你可以将一个坐标文件直接读入一个像这样的向量:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
char filename[] = "coordinates.txt";
std::vector<CoordinatePair> v;
std::ifstream ifs(filename);
if (ifs) {
std::copy(std::istream_iterator<CoordinatePair>(ifs),
std::istream_iterator<CoordinatePair>(),
std::back_inserter(v));
}
else {
std::cerr << "Couldn't open " << filename << " for reading\n";
}
// Now you can work with the contents of v
}
回答by gsamaras
Expanding on the accepted answer, if the input is:
如果输入是:
1,NYC
2,ABQ
...
you will still be able to apply the same logic, like this:
您仍然可以应用相同的逻辑,如下所示:
#include <fstream>
std::ifstream infile("thefile.txt");
if (infile.is_open()) {
int number;
std::string str;
char c;
while (infile >> number >> c >> str && c == ',')
std::cout << number << " " << str << "\n";
}
infile.close();
回答by Vijay Bansal
Although there is no need to close the file manually but it is good idea to do so if the scope of the file variable is bigger:
虽然不需要手动关闭文件,但如果文件变量的范围更大,最好这样做:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
回答by Universus
This answer is for visual studio 2017 and if you want to read from text file which location is relative to your compiled console application.
此答案适用于 Visual Studio 2017,如果您想从文本文件中读取哪个位置相对于您编译的控制台应用程序。
first put your textfile (test.txt in this case) into your solution folder. After compiling keep text file in same folder with applicationName.exe
首先将您的文本文件(在本例中为 test.txt)放入您的解决方案文件夹中。编译后将文本文件保存在与 applicationName.exe 相同的文件夹中
C:\Users\"username"\source\repos\"solutionName"\"solutionName"
C:\Users\"用户名"\source\repos\"solutionName"\"solutionName"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile;
// open the file stream
inFile.open(".\test.txt");
// check if opening a file failed
if (inFile.fail()) {
cerr << "Error opeing a file" << endl;
inFile.close();
exit(1);
}
string line;
while (getline(inFile, line))
{
cout << line << endl;
}
// close the file stream
inFile.close();
}
回答by mjr2000
This is a general solution to loading data into a C++ program, and uses the readline function. This could be modified for CSV files, but the delimiter is a space here.
这是将数据加载到 C++ 程序的通用解决方案,并使用 readline 函数。这可以针对 CSV 文件进行修改,但这里的分隔符是一个空格。
int n = 5, p = 2;
int X[n][p];
ifstream myfile;
myfile.open("data.txt");
string line;
string temp = "";
int a = 0; // row index
while (getline(myfile, line)) { //while there is a line
int b = 0; // column index
for (int i = 0; i < line.size(); i++) { // for each character in rowstring
if (!isblank(line[i])) { // if it is not blank, do this
string d(1, line[i]); // convert character to string
temp.append(d); // append the two strings
} else {
X[a][b] = stod(temp); // convert string to double
temp = ""; // reset the capture
b++; // increment b cause we have a new number
}
}
X[a][b] = stod(temp);
temp = "";
a++; // onto next row
}