7
votes

Lire le fichier en arrière (dernière ligne en premier)

Fichier ressemble à ceci:

ABCD
Efgh
ijkl

Je veux lire le fichier à l'aide de C de sorte qu'il soit lu la dernière ligne en premier:

ijkl
Efgh
ABCD

Je ne peux pas sembler trouver une solution qui n'utilise pas un tableau pour le stockage. S'il vous plaît aider.

Edit0: Merci pour toutes les réponses. Juste pour vous faire savoir, je suis celui qui crée ce fichier. Alors, puis-je créer d'une manière c'est dans l'ordre inverse? Est-ce possible?


5 commentaires

Voir Connexes: Stackoverflow.com/Questtions/136168/...


Il existe déjà une utilitaire de ligne de commande appelée tac (le revers du chat). Vous pouvez récupérer le code source pour cela et étudier comment ce programme résout le problème.


Y a-t-il une raison que vous êtes au genou vous-même de ne pas pouvoir utiliser un tableau?


@hlovdal: Merci, regardant dans tac source.


@Mu est trop court: car le nombre de lignes peut être énorme


6 Réponses :


13
votes

Cela va comme ça:

  1. recherche à un octet avant la fin du fichier en utilisant Fseek . Il n'y a aucune garantie que la dernière ligne aura une EOL afin que le dernier octet ne comporte pas vraiment d'importance.
  2. lire un octet en utilisant fgetc. / code> .
  3. Si cet octet est un EOL, la dernière ligne est une seule ligne vide et vous l'avez.
  4. Utilisez fsek à nouveau pour revenir en arrière deux octets et vérifier cet octet avec fget .
  5. Répétez ce qui précède jusqu'à ce que vous trouviez un eol. Lorsque vous avez un EOL, le pointeur de fichier sera au début de la ligne suivante (de la fin).
  6. ...
  7. profit.

    Fondamentalement, vous devez continuer à faire (4) et (5) tout en gardant une trace de l'endroit où vous étiez lorsque vous avez trouvé le début d'une ligne afin que vous puissiez vous chercher avant de commencer votre numérisation au début de la ligne suivante.

    Tant que vous ouvrez votre fichier en mode texte, vous ne devriez pas avoir à vous inquiéter de MultiByte EOLS sur Windows (merci pour le rappel M. Lutz).

    Si vous recevez une entrée non désapprouvée (telle qu'un tuyau), vous n'avez pas de chance, à moins que vous ne souhaitiez de jeter votre entrée dans un fichier temporaire en premier.

    Vous pouvez donc le faire mais c'est plutôt laid.

    Vous pouvez faire à peu près la même chose en utilisant MMAP et un pointeur si vous avez MMAP disponible et le "fichier" avec lequel vous travaillez est mappable. La technique serait à peu près la même: commencez à la fin et revenir en arrière pour trouver la fin de la ligne précédente.

    re: "Je suis celui qui crée ce fichier. Alors, puis-je créer de manière à ce que c'est dans l'ordre inverse? Est-ce possible?"

    Vous rencontrerez les mêmes types de problèmes, mais ils seront pires. Les fichiers en C sont des listes séquentielles intrinsèquement des octets qui commencent au début et vont à la fin; Vous essayez de travailler contre cette propriété fondamentale et d'aller contre les fondamentaux n'est jamais amusant.

    Avez-vous vraiment besoin de vos données dans un fichier texte brut? Peut-être avez-vous besoin de texte / plain comme la sortie finale, mais tout au long de la situation? Vous pouvez stocker les données dans un fichier binaire indexé (éventuellement même une base de données SQLITE), puis vous n'avez à vous soucier que de garder (ou de fenêtrer) l'index en mémoire et il est peu probable qu'il s'agisse d'un problème (et si c'est le cas, utilisez-le. une "vraie" base de données); Ensuite, lorsque vous avez toutes vos lignes, il suffit d'inverser l'index et de partir.


4 commentaires

Votre solution n'est pas efficace car le fseek est une opération lente et que vous le faites pour chaque octet dans le fichier.


@Skizz: Je n'ai jamais dit que c'était efficace mais j'ai dit que c'était laid. Avez-vous quelque chose de mieux qui n'utilise pas de tableau? Il y a toujours mmap je suppose.


Les fonctions standard F * io, lorsque le fichier * est ouvert dans le mode texte (non binaire), effectuez automatiquement les conversions EOL pour vous.


@Chris: Droite, merci. Été longue depuis que je devais faire face à c sous Windows.



3
votes

en pseudocode:

open input file
while (fgets () != NULL)
{
   push line to stack
}
open output file
while (stack no empty)
{
   pop stack
   write popped line to file
}


3 commentaires

Cette réponse est mauvaise à bien des égards: il utilise beaucoup de mémoire alors qu'il n'y a pas besoin de le besoin. Chercher n'est pas lent. Peut-être sous Windows, ou systèmes de fichiers réseau, mais pas sur UNIX.


@Coroos: True, la fonction de recherche elle-même n'est pas lente, il suffit de l'utiliser pour lire un fichier en arrière, c'est-à-dire où cherchez-vous? Lisez le fichier un personnage à la fois de la fin au début? Cela peut être fait et bien fait, mais le code commence à avoir un peu compliqué. Ici, "efficace" est également une mesure de la complexité du code, ce code est trivial.


Les blocs de lecture des données provenant des avances finales, puis la numérisation des blocs en arrière est plus complexe. Le support de stockage affectera probablement la vitesse de l'algorithme plus que le code, la lecture d'un fichier en avant n'est jamais plus lente (pas toujours plus rapide, mais jamais plus lent). La lecture de l'approche à l'envers des fichiers sera supérieure en cas de validation de RAM disponible. Balançoires et ronds-points.



-1
votes

Les œuvres suivantes pour moi sur Linux, où le séparateur de ligne de fichier texte est "\ n".

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

void readfileinreverse(FILE *fp)
{
    int i, size, start, loop, counter;
    char *buffer;
    char line[256];
    start = 0;
    fseek(fp, 0, SEEK_END);
    size = ftell(fp);

    buffer = malloc((size+1) * sizeof(char));

    for (i=0; i< size; i++)
    {
        fseek(fp, size-1-i, SEEK_SET);
        buffer[i] = fgetc(fp);

        if(buffer[i] == 10)
        {
           if(i != 0)
           {
            counter = 0;        
            for(loop = i; loop > start; loop--)
            {
                if((counter == 0) && (buffer[loop] == 10))
                {
                    continue;
                }               
                line[counter] = buffer[loop];
                counter++;
            }
            line[counter] = 0;
            start = i;
            printf("%s\n",line);
           }
        }
    }

    if(i > start)
    {    
        counter = 0;
        for(loop = i; loop > start; loop--)
        {       
            if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0)))
            {
                continue;
            }               
            line[counter] = buffer[loop];
            counter++;
        }
        line[counter] = 0;
        printf("%s\n",line);

        return;
    }
}

int main()
{
    FILE *fp = fopen("./1.txt","r");
    readfileinreverse(fp);
    return 0;
}


1 commentaires

Il me semble que vous avez une fuite de mémoire. Vous utilisez masloc () pour allouer la mémoire pour tampon , mais à la fin de la fonction readfileinReverse () Vous n'appelez pas Gratuit (tampon) .



1
votes

Le code suivant doit effectuer l'inversion nécessaire:

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

int main(int argc, char *argv[])
{
        FILE *fd;
        char len[400];
        int i;

        char *filename = argv[1];
        int ch;
        int count;

        fd = fopen(filename, "r");
        fseek(fd, 0, SEEK_END);
        while (ftell(fd) > 1 ){
                fseek(fd, -2, SEEK_CUR);
                if(ftell(fd) <= 2)
                        break;
                ch =fgetc(fd);
                count = 0;
                while(ch != '\n'){
                        len[count++] = ch;
                        if(ftell(fd) < 2)
                                break;
                        fseek(fd, -2, SEEK_CUR);
                        ch =fgetc(fd);
                }
                for (i =count -1 ; i >= 0 && count > 0  ; i--)
                        printf("%c", len[i]);
                printf("\n");
        }
        fclose(fd);
}


0 commentaires

-2
votes

Peut-être que le problème est-il inverse le contenu du fichier entier juste comme une corde

  1. Définissez une variable de chaîne de type avec la taille de votre fichier
  2. Obtenez le contenu du fichier et stockez dans la variable
  3. Utilisez STRREV () pour inverser la chaîne.

    Vous pouvez ensuite afficher la sortie ou même l'écrire dans un fichier. Le code va comme ceci: xxx


1 commentaires

Strrev est non standard C et ne devrait pas être suggéré à cause de cela. Nécessite également de coder autour de la taille du fichier.



-1
votes

Je sais que cette question a été répondue, mais la réponse acceptée ne contient pas d'extrait de code et les autres extraits se sentent trop complexes. Ceci est ma mise en œuvre:

#include <stdio.h>

long file_size(FILE* f) {
    fseek(f, 0, SEEK_END); // seek to end of file
    long size = ftell(f); // get current file pointer
    fseek(f, 0, SEEK_SET); // seek back to beginning of file
    return size;
}

int main(int argc, char* argv[]) {
    FILE *in_file = fopen(argv[1], "r");
    long in_file_size = file_size(in_file);
    printf("Got file size: %ld\n", in_file_size);

    // Start from end of file
    fseek(in_file, -1, SEEK_END); // seek to end of file
    for (int i = in_file_size; i > 0; i--) {
        char current_char = fgetc(in_file); // This progresses the seek location
        printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
        fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
    }
    printf("Done\n");

    fclose(in_file);
}


1 commentaires

qui va inverser chaque char et le PO veut inverser des lignes