Yanıtlar:
İlk önce aşağıdakileri yapın ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
İki standart yöntem şunlardır:
Her satırın iki sayıdan oluştuğunu ve jetonla jetonu okuduğunu varsayın:
int a, b;
while (infile >> a >> b)
{
// process pair (a,b)
}
Dize akışlarını kullanarak satır tabanlı ayrıştırma:
#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)
}
(1) ve (2) 'yi karıştırmamalısınız, çünkü jeton tabanlı ayrıştırma yeni satırları kaldırmaz, bu nedenle getline()
jeton tabanlı ekstraksiyon sizi bir hattı zaten.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
Yapının açıklaması ve hataların ele alınması ile ilgili olarak lütfen bu (benim) makaleye bir göz atın: gehrcke.de/2011/06/… (Sanırım bunu burada göndermek için vicdanımın olması gerekmiyor, hatta biraz daha bu yanıtı tarihlendirir).
ifstream
Bir dosyadan veri okumak için kullanın :
std::ifstream input( "filename.ext" );
Gerçekten satır satır okumaya ihtiyacınız varsa, bunu yapın:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
Ama muhtemelen sadece koordinat çiftlerini çıkarmanız gerekir:
int x, y;
input >> x >> y;
Güncelleme:
Kodunuzda kullanın ofstream myfile;
, ancak o
in ofstream
anlamına gelir output
. Dosyadan (giriş) okumak istiyorsanız kullanın ifstream
. Hem okumak hem de yazmak istiyorsanız kullanın fstream
.
C ++ 'da bir dosyayı satır satır okumak bazı farklı yollarla yapılabilir.
En basit yaklaşım std :: getstream () çağrılarını kullanarak bir std :: ifstream ve loop'u açmaktır. Kod temiz ve anlaşılması kolaydır.
#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();
}
Başka bir olasılık Boost kütüphanesini kullanmaktır, ancak kod biraz daha ayrıntılı hale gelir. Performans yukarıdaki koda oldukça benzerdir (std :: getline () ile döngü).
#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();
}
}
}
Yazılımınız için performans kritikse, C dilini kullanmayı düşünebilirsiniz. Bu kod yukarıdaki C ++ sürümlerinden 4-5 kat daha hızlı olabilir, aşağıdaki karşılaştırmaya bakın
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);
Yukarıdaki kod ile bazı performans kriterleri yaptım ve sonuçlar ilginç. 100.000 satır, 1.000.000 satır ve 10.000.000 satır metin içeren ASCII dosyaları ile kodu test ettim. Her metin satırı ortalama 10 kelime içerir. Program -O3
optimizasyon ile derlenir ve çıktısı /dev/null
kayıt süresi değişkenini ölçümden kaldırmak için yönlendirilir . Son olarak, her bir kod parçası, her satırı printf()
tutarlılık işleviyle günlüğe kaydeder .
Sonuçlar, her kod parçasının dosyaları okumak için aldığı süreyi (ms cinsinden) gösterir.
İki C ++ yaklaşımı arasındaki performans farkı minimaldir ve uygulamada herhangi bir fark yaratmamalıdır. C kodunun performansı, ölçütü etkileyici kılan şeydir ve hız açısından bir oyun değiştirici olabilir.
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()
tutarlılık için her durumda işlevi kullanmak için kodu düzenledim . Ayrıca std::cout
her durumda kullanmayı denedim ve bu kesinlikle hiçbir fark yaratmadı. Metinde az önce açıkladığım gibi, programın çıktısı gider, /dev/null
böylece satırları yazdırma süresi ölçülmez.
cstdio
. Ayarı denemeliydiniz std::ios_base::sync_with_stdio(false)
. Sanırım çok daha iyi performanslar elde edersiniz ( Senkronizasyon kapatıldığında uygulama tanımlı olduğu için garanti edilmez ).
Koordinatlarınız çift olarak bulunduğundan, neden onlar için bir yapı yazmıyorsunuz?
struct CoordinatePair
{
int x;
int y;
};
Sonra istreams için aşırı yüklenmiş bir çıkarma operatörü yazabilirsiniz:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
Ve sonra bir koordinat dosyasını doğrudan şöyle bir vektöre okuyabilirsiniz:
#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
Akıştaki iki jetonu okumak mümkün olmadığında ne olur operator>>
? Bir geri izleme ayrıştırıcısı ile nasıl çalışabilir (yani operator>>
başarısız olduğunda, akışı önceki konum sonuna geri döndürmek yanlış veya bunun gibi bir şey)?
int
jetonu okumak mümkün değilse , is
akış değerlendirilir false
ve okuma döngüsü bu noktada sona erer. operator>>
Bireysel okumaların dönüş değerini kontrol ederek bunu içinde tespit edebilirsiniz . Akışı geri almak isterseniz arama yaparsınız is.clear()
.
operator>>
söylemek daha doğru olur is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
Eğer giriş akışı boşluk-atlama modunda olduğunu varsayıyoruz aksi beri.
Girdi şu ise, kabul edilen cevabı genişletmek:
1,NYC
2,ABQ
...
yine de aynı mantığı şu şekilde uygulayabileceksiniz:
#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();
Dosyayı manuel olarak kapatmaya gerek olmamasına rağmen, dosya değişkeninin kapsamı daha büyükse bunu yapmak iyi bir fikirdir:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
Bu cevap visual studio 2017 içindir ve derlenmiş konsol uygulamanıza göre hangi konumun metin dosyasından okumak istiyorsanız.
önce metin dosyanızı (bu durumda test.txt) çözüm klasörünüze koyun. Derledikten sonra metin dosyasını applicationName.exe ile aynı klasörde tut
C: \ Users \ "kullanıcı adı" \ kaynak \ repo \ "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();
}
Bu, bir C ++ programına veri yüklemek için genel bir çözümdür ve readline işlevini kullanır. Bu CSV dosyaları için değiştirilebilir, ancak sınırlayıcı burada bir boşluktur.
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
}