3
votes

Comment lire une date à partir d'un fichier en c

Je lis un fichier dans un programme utilisant C. dans le fichier J'ai des dates chacune dans une ligne distincte exactement comme ceci:

#include <stdio.h>
#include <stdlib.h>
void FileRead(FILE *pr)
{
    char date [15];
    fgets(date,15,pr);
    printf("date : %s", date);

}
int main()
{
   char x;
   FILE *pr;
   pr=fopen("mytextfile.txt","r");
   if(pr==NULL)
   {
       printf("File can not be opened.");
       return 0;
   }
  while(scanf("%c", &x))
    {
        switch(x)
        {

        case 'v' :
            FileRead(pr);
        break;

        case 'k' :
            return 0;

        }
    }
fclose(pr);
    return 0;
}

Maintenant, je veux que le programme les lise comme dates et trouvez la différence entre la date actuelle et ces dates. est-il possible de convertir ces dates dans un format lisible par C? quelque chose comme ceci: 2019.01.01 Actuellement, je le lis en utilisant fgets et je ne parviens pas à le convertir au format ci-dessus. Voici mon code:

20190101
20190304
20180922


3 Réponses :


1
votes

Une fois que vous avez char * via fgets , utilisez atoi pour convertir en entier. Ensuite, vous avez la date au format AAAAMMJJ. Ensuite, vous pouvez faire

const int day = dateYYYYMMDD % 100;
const int month = (dateYYYYMMDD % 10000)/100;
const int year = dateYYYYMMDD / 10000;

Vous pouvez utiliser C Date et heure fonctions pour obtenir la date actuelle.

Pour faire la différence entre la date actuelle et ces dates, une option consiste à convertir toutes les dates en Date julienne et ensuite faire une différence de nombre sur les dates juliennes.

Si obtenir la date julienne est difficile, normaliser à la même année (en ajoutant 365 ou 366 basé sur l'année est bissextile ou non à mesure que vous passez d'une année inférieure à une année supérieure). Arrivez ensuite au même mois, puis faites la différence de jour.


1 commentaires

Éviter d'utiliser atoi , c'est fournir zéro la possibilité de valider la conversion. Utilisez plutôt strtol . Ou bien que ce ne soit pas génial, mais mieux serait de lire avec fgets et l'analyse avec sscanf . Au moins, vous avez une mesure du succès / échec de la conversion.



0
votes

Le résultat est, il vous suffit de boucler les lignes du fichier et de définir une condition if dans celui-ci

20190315
20190304
20180922

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

int main(void)
{
    char buff[20];
    time_t now = time(NULL);

    strftime(buff, 20, "%Y%m%d\n", localtime(&now));
    printf("Today : %s \n\n", buff);

    static const char filename[] = "file.txt";
    FILE *file = fopen(filename, "r");

    if (file != NULL)
    {
        char line[128]; /* or other suitable maximum line size */
        while (fgets(line, sizeof line, file) != NULL) /* read a line */
        {
            fputs(line, stdout); /* write the line */

            if (strcmp(line, buff) == 0)
                printf("\nThis line of date equal to current date\n");

        }
        fclose(file);
    }
    else
    {
        perror(filename); /* why didn't the file open? */
    }
    return 0;
}


5 commentaires

référence indéfinie à getline.


La réponse est correcte, je viens de l'exécuter dans mon système Ubuntu, quelle est votre plate-forme? Les fenêtres ? linux? Mac ? c'est l'erreur de configuration du système! changez #define _GNU_SOURCE avec votre source à l'aide de [link] ( stackoverflow.com/questions/13112784/... )


Il imprime la date actuelle, mais le problème est toujours là, imaginez maintenant qu'il y a un mot dans la première ligne et un mot dans la deuxième ligne et la date dans la troisième ligne. maintenant, comment lire uniquement la troisième ligne (date) et soustraire le nombre de jours de la date actuelle à cela?


problème encore des moyens? référence indéfinie à getline. ??


Non, c'est bien maintenant. et s'il y a un mot dans la première ligne et un mot dans la deuxième ligne et la date dans la troisième ligne. maintenant, comment lire uniquement la troisième ligne (date) et soustraire le nombre de jours de la date actuelle à cela?



1
votes

Le moyen le plus simple d'approcher la différence d'ici là est de lire les dates du fichier et de les analyser en mois, jour et année ( m, j, y ). Si vous n'allez pas faire une validation complète de chaque conversion, un moyen simple de séparer l'année à 4 chiffres et le mois et le jour à 2 chiffres consiste à utiliser fscanf avec le champ approprié -width modificateurs pour limiter la conversion au nombre de chiffres requis, par exemple

$ ./bin/time_from_now2 dat/3dates-w-headers.txt
non-date line: This file contains dates to read and convert to days.
non-date line: The file also contains this description and dates in the format:
non-date line:
non-date line: yyyymmdd
date[1] 01/01/2019 is  6348645.00 sec (73.4797 days) from now.
date[2] 03/04/2019 is   991845.00 sec (11.4797 days) from now.
date[3] 09/22/2018 is 15078645.00 sec (174.521 days) from now.

Ensuite, tout ce qui est nécessaire dans la boucle est de renseigner le struct tm code > avec les valeurs de l'année, du mois et du jour (en vous rappelant de soustraire 1900 de l'année, et de définir chacun des membres heure, minute et seconde sur zéro et le membre heure d'été sur -1 ). Une fonction simple peut le faire et renvoyer time_t après avoir appelé mktime , par exemple

$ cat dat/3dates-w-headers.txt
This file contains dates to read and convert to days.
The file also contains this description and dates in the format:

yyyymmdd
20190101
20190304
20180922

Pour terminer, tout ce dont vous avez besoin est pour obtenir les valeurs time_t et appelez difftime pour obtenir la différence en secondes entre l'heure actuelle et l'heure lue dans le fichier sous la forme d'une valeur double . En continuant la boucle dans main () , par exemple

#include <stdio.h>
#include <time.h>

#define MAXC 1024u  /* if you need a constant, #define one (or more) */

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d, 
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}

int main (int argc, char **argv) {
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    int y, m, d, n = 1;
    char buf[MAXC];     /* buffer to hold each line read from file */

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        /* if line isn't a date line, just output line as non-date line */
        if (sscanf (buf, "%4d%2d%2d", &y, &m, &d) != 3) {
            printf ("non-date line: %s", buf);
            continue;
        }
        time_t  now = time(NULL),
                then = fill_broken_down_time (y, m, d);
        double secs = difftime (now, then); /* get seconds between dates */
        printf ("date[%d] %02d/%02d/%04d is %11.2f sec (%g days) from now.\n", 
                n++, m, d, y, secs, secs / 86400.0);
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

En le mettant complètement, vous pouvez faire quelque chose comme:

./yourprogram < your_date_file


11 commentaires

Je ne parviens pas à ouvrir le fichier. plus je veux montrer la différence en jours. et si la première ligne est un nom, le deuxième nom de famille et la troisième une date?


Bravo, David! cela semble une solution incroyable et devrait être la réponse. quelque chose d'autre m'est venu à l'esprit, pouvons-nous utiliser des instructions if en même temps tout en lisant des fichiers en utilisant fgets et scanf ? si oui, je voudrais ajouter autre chose à cette question.


Bien sûr, c'est la beauté de la programmation, vous pouvez ajouter toutes les conditions supplémentaires que vous souhaitez dans n'importe quelle boucle. La condition que je viens de vérifier vérifie si la ligne ne parvient pas à analyser y, m d - si c'est le cas, je l'imprime comme expliqué ci-dessus et je vais chercher la ligne suivante. Vous pouvez changer cela comme vous le souhaitez. Essayez-le et si vous avez des problèmes, faites-le moi savoir.


Fonctionne bien maintenant. Je vous dois beaucoup. Je vous remercie.


D'ACCORD. J'ai ajouté quelques valeurs dans le fichier. la première ligne est le nom, la deuxième est le numéro de plaque comme AA333BB , la troisième est la valeur bool 1 ou 0 , quatrième est le coût 100,00 et la date finale. dans mon cas, il s'agit d'un record pour un client. J'en ai beaucoup dans le même fichier mais séparés seulement par une ligne vide. Maintenant, je veux imprimer le nom et le numéro de plaque de chaque enregistrement, si la date est plus d'un an à partir de maintenant. et bien sûr je veux vérifier si le type est 1 je dois imprimer un vlaue et si son 0 je devrais en imprimer un autre. Je ne suis pas en mesure de comprendre votre exemple dans ce cas, pouvons-nous faire cela?


si le type est 1, je veux multiplier le coût par 1,5 et s'il vaut 0 je veux qu'il soit multiplié par 2,5 . Je sais que cela a l'air bizarre mais dites-moi si c'est possible.


Ce que vous voudrez faire est d'utiliser le compteur n pour contrôler ce que vous lisez. Vous pouvez simplement faire while (fgets (..)) {switch (n) {case 1: / * gérer la 1ère ligne * / break; cas 2: / * gérer le numéro de plaque * / break, .... L'autre option est de tester le contenu de chaque ligne - mais si vous savez qu'elle a un format fixe et ce que les lignes contiennent, alors un simple compteur et switch ou un if (n == 1) ... else if (n == 2) ... else if ... est un plus simple marche à suivre.


Sur votre multiplicateur de coût, vous pouvez rendre le nom de fichier obligatoire comme argv [1] (1er argument du programme), puis passer 0 ou 1 comme < code> argv [2] (2ème argument) définissant une valeur par défaut de '0' ou '1' si aucun 2ème argument n'est passé. (par exemple, int multflag = argc> 2? argv [2] [0]: '1' ; (qui définit simplement multflag au 1er caractère de argv [ 2] si fourni ou '1' par défaut en utilisant l'opérateur ternaire . Ensuite, vous pouvez simplement vérifier if (multflag == '0' ) val * 2.5; else val * 1.5; Rien d'extraordinaire. (La bonne manière serait d'utiliser getopt et de configurer un schéma de prise d'options - mais c'est pour plus tard....)


Et notez ... les guillemets simples autour de '0' et '1' (vous lisez les arguments comme des caractères de la ligne de commande) donc lorsque vous comparez le multflag assurez-vous de comparer avec "0" ou "1" :)


Sûr. Je vais essayer de vous faire savoir s'il y a eu un problème. :)


@ DavidC.Rankin J'ai posé la question ici stackoverflow.com/questions/55191612/...