FICHIER TEXTE EN LECTURE

1 1 1
1.2 -2.3 0.4
-2 -3 -4
+0 -2 8.85
2.345

Mon code:

#include <iostream>
#include <fstream>

using namespace std;

double readFile(ifstream &myfile, double &a, double &b, double &c);
int main()
{
    int counter = 0;
    double a, b, c;
    string line, inputFile, outputFile;

    cout << "Enter the name of your input file: ";
    cin >> inputFile;

    cout << "Enter the name of your output file: ";
    cin >> outputFile;

    ifstream myfile(inputFile);
    if(myfile.is_open())
    {
        while(!myfile.eof())
        {
            readFile(myfile, a, b, c, counter);
            calculations(a, b, c);
        }


    }
    else cout << "unable to open file";
    return 0;
}

double readFile(ifstream &myfile, double &a, double &b, double &c)
{
    //Reads one line of the file
    myfile >> a >> b >> c;
    cout << a << " " << b << " " << c << endl;

}

Ce que je veux faire, c'est que si la dernière ligne n'a pas 3 valeurs, je veux avoir une sorte de code d'arrêt où il arrête le traitement s'il a moins de 3 valeurs et les valeurs restantes de la ligne précédente ne seront pas attribuées

c++
1
Marcos Hernandez 30 août 2020 à 10:07

3 réponses

Meilleure réponse

Votre plus gros problème est que >> ignore les espaces au début, donc il ne fait pas la différence entre un ' ' (espace) ou '\n' - ce n'est que des espaces. Pour le gérer correctement, vous devez lire chaque ligne dans un std::string puis créer un std::stringstream à partir de la ligne.

Ensuite, lisez vos trois double valeurs de std::stringstream avec >>. De cette façon, vous ne pouvez pas lire plus de valeurs double que celles présentes dans la ligne. Sinon, si vous essayez simplement d'utiliser >>, vous lirez volontiers 2 double valeurs d'une ligne et la troisième de la suivante sans aucune indication que cela se produise.

Vous devez ensuite que votre fonction indique le succès / l'échec de la lecture des trois valeurs double de la ligne. Un type de retour bool est tout ce dont vous avez besoin. Si vous lisez trois valeurs double valides, renvoyez true et faites votre calculations() sinon, si vous renvoyez false, arrêtez d'essayer de lire à partir du fichier.

Un court exemple serait:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

bool read3doubles (std::ifstream& f, double& a, double& b, double& c)
{
    std::string line {};                /* std::string to hold line */
    
    if (getline (f, line)) {            /* if line read from file */
        std::stringstream ss(line);     /* create stringstream from line */
        if (ss >> a >> b >> c)          /* if 3 doubles read from line */
            return true;                /* return true */
    }
    
    return false;   /* otherwise, return false */
}

void calculations (double& a, double& b, double& c)
{
    std::cout << a << "  " << b << "  " << c << '\n';
}

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least 1 argument given */
        std::cerr << "error: insufficient number of arguments.\n"
                    "usage: " << argv[0] << " <filename>\n";
        return 1;
    }

    std::ifstream f (argv[1]);          /* open file-stream with 1st argument */
    double a, b, c;
    
    if (!f.good()) {    /* validate file open for reading */
        std::cerr << "errro: file open failed '" << argv[1] << "'.\n";
        return 1;
    }

    while (read3doubles(f, a, b, c))    /* while 3 doubles read from file */
        calculations (a, b, c);         /* do your calculation */
    
}

( remarque: la fonction calculations() ne renvoie que les trois doubles une fois la lecture réussie)

Exemple d'utilisation / de sortie

En utilisant votre entrée dans le fichier dat/3doubles.txt, vous auriez:

$ ./bin/read3doubles dat/3doubles.txt
1  1  1
1.2  -2.3  0.4
-2  -3  -4
0  -2  8.85

Faites-moi savoir si vous avez d'autres questions.

1
David C. Rankin 30 août 2020 à 08:05

J'ai ajouté une fonction différente qui coupe une ligne par espace et les convertit en nombres. Votre fonction principale reste en grande partie inchangée. Bien que j'aie apporté quelques modifications comme l'ajout d'un std::vector, retour anticipé pour supprimer une certaine imbrication.

De plus, j'ai changé la condition principale while de eof à std::getline.

  • Les opérations sur std::string_view sont très bon marché.

  • De cette façon, vous pouvez vérifier sur chaque ligne que le nombre de valeurs lues est toujours ce dont vous avez besoin.

  • Pour une mauvaise entrée, vous pouvez facilement déboguer si une ligne / mot n'est pas un nombre en l'imprimant dans le récupérateur d'exceptions.

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

void read_values(std::string_view line, std::vector<double> &values);
void calculations(int, int, int);
int main()
{
  string inputFile, outputFile;

  cout << "Enter the name of your input file: ";
  cin >> inputFile;

  cout << "Enter the name of your output file: ";
  cin >> outputFile;

  ifstream myfile(inputFile);
  if (!myfile.is_open()) {
    cout << "unable to open file";
    return -1;
  }

  std::string line;
  std::vector<double> values;
  while (std::getline(myfile, line, '\n')) {
    read_values(line, values);
    std::cout << values.size();
  }
  return 0;
}

void read_values(std::string_view line, std::vector<double> &values)
{
  while (!line.empty()) {
    const std::string_view::size_type pos_space{line.find(' ')};
    try {
      values.push_back(std::stod(std::string(line.substr(0, pos_space))));
    }
    catch (const std::invalid_argument &ex) {
      std::cout << ex.what() << std::endl;
      return;
    }
    line.remove_prefix(pos_space + 1);
  }
}

1
puio 30 août 2020 à 08:15

std::istream définit failbit lorsque operator>> n'a pas réussi à extraire la valeur du flux. Dans votre code, failbit sera défini s'il ne parvient pas à analyser 3 valeurs qui peuvent être analysées en double, et vous pouvez demander si failbit est défini par std::failbit().

double readFile(ifstream &myfile, double &a, double &b, double &c)
{
    myfile >> a >> b >> c;

    if(myfile.fail())
    {
        // failbit is set if one of a, b or c is not parsed successfully.
        // do some stop code here.
    }

    cout << a << " " << b << " " << c << endl;

}

N'oubliez pas que std::istream ne fait rien pour une opération ultérieure si failbit est défini. Si vous devez continuer à lire à partir du flux, vous devez effacer failbit en appelant std::clear().

1
John Park 30 août 2020 à 07:43