Câu trả lời:
Đầu tiên, tạo một ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
Hai phương pháp tiêu chuẩn là:
Giả sử rằng mỗi dòng bao gồm hai số và đọc mã thông báo bằng mã thông báo:
int a, b;
while (infile >> a >> b)
{
// process pair (a,b)
}
Phân tích cú pháp dựa trên dòng, sử dụng luồng chuỗi:
#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)
}
Bạn không nên kết hợp (1) và (2), vì phân tích cú pháp dựa trên mã thông báo không ngấu nghiến dòng mới, do đó bạn có thể kết thúc bằng các dòng trống giả nếu bạn sử dụng getline()
sau khi trích xuất dựa trên mã thông báo đã đưa bạn đến cuối dòng đã.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
cấu trúc và liên quan đến việc xử lý lỗi, vui lòng xem bài viết này (của tôi): gehrcke.de/2011/06/. (Tôi nghĩ rằng tôi không cần phải có lương tâm xấu khi đăng bài này ở đây, nó thậm chí còn hơi trước ngày trả lời này).
Sử dụng ifstream
để đọc dữ liệu từ một tệp:
std::ifstream input( "filename.ext" );
Nếu bạn thực sự cần đọc từng dòng, thì hãy làm điều này:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
Nhưng có lẽ bạn chỉ cần trích xuất các cặp tọa độ:
int x, y;
input >> x >> y;
Cập nhật:
Trong mã của bạn, bạn sử dụng ofstream myfile;
, tuy nhiên o
trong ofstream
là viết tắt cho output
. Nếu bạn muốn đọc từ tập tin (đầu vào) sử dụng ifstream
. Nếu bạn muốn cả đọc và viết sử dụng fstream
.
Đọc một dòng tệp theo dòng trong C ++ có thể được thực hiện theo một số cách khác nhau.
Cách tiếp cận đơn giản nhất là mở std :: ifstream và loop bằng các lệnh gọi std :: getline (). Mã sạch và dễ hiểu.
#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();
}
Một khả năng khác là sử dụng thư viện Boost, nhưng mã sẽ dài dòng hơn một chút. Hiệu suất khá giống với mã ở trên (Lặp lại với 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();
}
}
}
Nếu hiệu suất là quan trọng đối với phần mềm của bạn, bạn có thể xem xét sử dụng ngôn ngữ C. Mã này có thể nhanh hơn 4-5 lần so với các phiên bản C ++ ở trên, xem điểm chuẩn bên dưới
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);
Tôi đã thực hiện một số điểm chuẩn hiệu suất với mã ở trên và kết quả rất thú vị. Tôi đã kiểm tra mã với các tệp ASCII chứa 100.000 dòng, 1.000.000 dòng và 10.000.000 dòng văn bản. Mỗi dòng văn bản chứa trung bình 10 từ. Chương trình được biên dịch với -O3
tối ưu hóa và đầu ra của nó được chuyển tiếp /dev/null
để loại bỏ biến thời gian ghi nhật ký khỏi phép đo. Cuối cùng, nhưng không kém phần quan trọng, mỗi đoạn mã ghi lại từng dòng với printf()
chức năng để thống nhất.
Kết quả cho thấy thời gian (tính bằng ms) mà mỗi đoạn mã đã dùng để đọc các tệp.
Sự khác biệt về hiệu năng giữa hai cách tiếp cận C ++ là tối thiểu và không nên tạo ra bất kỳ sự khác biệt nào trong thực tế. Hiệu suất của mã C là những gì làm cho điểm chuẩn ấn tượng và có thể là một thay đổi trò chơi về tốc độ.
10K lines 100K lines 1000K lines
Loop with std::getline() 105ms 894ms 9773ms
Boost code 106ms 968ms 9561ms
C code 23ms 243ms 2397ms
std::cout
vs printf
.
printf()
hàm trong mọi trường hợp cho thống nhất. Tôi cũng đã thử sử dụng std::cout
trong mọi trường hợp và điều này hoàn toàn không có sự khác biệt. Như tôi vừa mô tả trong văn bản, đầu ra của chương trình đi để /dev/null
thời gian in các dòng không được đo.
cstdio
. Bạn nên thử với thiết lập std::ios_base::sync_with_stdio(false)
. Tôi đoán bạn sẽ có được hiệu suất tốt hơn nhiều (Mặc dù điều đó không được đảm bảo vì nó được xác định theo triển khai khi tắt đồng bộ hóa).
Vì tọa độ của bạn thuộc về nhau như cặp, tại sao không viết một cấu trúc cho chúng?
struct CoordinatePair
{
int x;
int y;
};
Sau đó, bạn có thể viết một toán tử trích xuất quá tải cho iuxs:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
Và sau đó bạn có thể đọc một tệp tọa độ thẳng vào một vectơ như thế này:
#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
}
int
mã thông báo từ luồng trong operator>>
? Làm thế nào người ta có thể làm cho nó hoạt động với trình phân tích cú pháp quay lui (nghĩa là khi operator>>
thất bại, quay ngược lại luồng đến vị trí trước đó trả về false hoặc một cái gì đó tương tự)?
int
mã thông báo, thì is
luồng sẽ đánh giá false
và vòng đọc sẽ chấm dứt tại thời điểm đó. Bạn có thể phát hiện điều này trong operator>>
bằng cách kiểm tra giá trị trả về của các lần đọc riêng lẻ. Nếu bạn muốn cuộn lại luồng, bạn sẽ gọi is.clear()
.
operator>>
đó là chính xác hơn để nói is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
vì nếu không bạn đang giả định rằng dòng đầu vào của bạn đang ở chế độ khoảng trắng bỏ qua.
Mở rộng trên câu trả lời được chấp nhận, nếu đầu vào là:
1,NYC
2,ABQ
...
bạn vẫn có thể áp dụng logic tương tự, như thế này:
#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();
Mặc dù không cần phải đóng tệp theo cách thủ công nhưng bạn nên làm như vậy nếu phạm vi của biến tệp lớn hơn:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
Câu trả lời này dành cho visual studio 2017 và nếu bạn muốn đọc từ tệp văn bản, vị trí nào có liên quan đến ứng dụng bảng điều khiển được biên dịch của bạn.
đầu tiên đặt textfile của bạn (test.txt trong trường hợp này) vào thư mục giải pháp của bạn. Sau khi biên dịch, giữ tập tin văn bản trong cùng thư mục với applicationName.exe
C: \ Users \ "tên người dùng" \ 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();
}
Đây là một giải pháp chung để tải dữ liệu vào chương trình C ++ và sử dụng chức năng đọc. Điều này có thể được sửa đổi cho các tệp CSV, nhưng dấu phân cách là một khoảng trắng ở đây.
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
}