Pour mon implémentation de la commande tail shell sous Linux, j'ai besoin de lire un certain nombre de lignes/octets à la fin du fichier en utilisant l'entrée/la sortie du flux. Est-ce que quelqu'un a des suggestions sur la façon de le faire? Je soupçonne que j'ai besoin d'ouvrir un fichier et passer un paramètre au constructeur ifstream, mais je ne sais pas exactement quoi. Google n'a rien trouvé.Comment lire un nombre donné de lignes à la fin du fichier en utilisant des flux en C++?
Répondre
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
ifstream is("file.txt", ios::binary);
if (!is) {
cout << "Failed to open file" << endl;
return 1;
}
is.seekg(0, ios::end);
int len = is.tellg();
char c;
int n = 0;
ostringstream line;
int lines = 0;
for (int i = len - 1; i >= 0; --i) {
is.seekg(i, ios::beg);
is.get(c);
if (c == '\n' || i == 0) {
if (i < len - 1) {
if (i == 0) {
line << c;
}
string s = line.str();
cout << lines << ": " << string(s.rend() - n, s.rend()) << endl;
++lines;
n = 0;
line.seekp(0, ios::beg);
}
} else {
line << c;
++n;
}
}
is.close();
return 0;
}
recherche en arrière après le début du fichier (c'est-à-dire si le fichier a une taille inférieure à 4096 octets) est en fait non défini –
cela ne cherche pas le point de départ – jspcal
Je ne pense pas qu'il y ait un moyen facile d'aller à ce sujet, vous aurez probablement besoin de chercher à la fin du fichier, sauvegardez un « morceau » (une taille arbitraire, mais quelques kilo-octets peut-être), lisez ce "morceau" de données et commencez à chercher de nouveaux caractères, si vous n'avez pas trouvé assez, vous sauvegardez deux fois votre taille de morceau (rappelez-vous, vous avez lu, donc vous devez sauvegarder le celui que vous lisez, plus celui que vous voulez lire ensuite), et lisez dans un autre.
HTH
Depuis la queue doit travailler avec des tuyaux, que vous ne pouvez pas revenir en arrière, vous devrez garder un tampon de rotation des n dernières lignes que vous avez lu que vous videra sur EOF.
Cette méthode convient aux fichiers courts. Mais les fichiers volumineux nécessitent une technique différente. Vous devez chercher à la fin puis commencer à sauvegarder. –
Vous pouvez utiliser différentes techniques pour différents fichiers, mais celui que j'ai décrit est toujours requis pour des choses comme stdin. – Tobu
De plus, les devoirs n'ont pas besoin d'être performants, au moins, il ne l'a pas dit. – Potatoswatter
Ce problème est analogue au problème d'obtention des derniers noeuds n
d'une liste à liaison unique. Vous devez aller tout le chemin jusqu'à la fin avec un tampon de n
lignes, puis cracher les lignes de tampon.
cela montre comment vous le feriez en C++ ... lisez des morceaux successifs à la fin du fichier, puis scannez les morceaux pour trouver de nouvelles lignes. si un saut de ligne ne se trouve pas, une partie du morceau doit être maintenu autour et combiné avec le morceau suivant lu dans ...
//
// USAGE: lastln COUNT [FILE]
//
// Print at most COUNT lines from the end of FILE or standard input.
// If COUNT is -1, all lines are printed.
//
#include <errno.h>
#include <libgen.h>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(int argc, char **argv)
{
int ret = 0, maxLines = -1, len, count = 0, sz = 4096, lines = 0, rd;
istream *is;
ifstream ifs;
stringstream ss;
char *buf = NULL;
const char *prog = (argc > 0 && argv[0] ? basename(argv[0]) : "");
string line;
if (argc > 1) {
if ((maxLines = atoi(argv[1])) == 0) {
goto end;
}
}
if (argc > 2 && !(argv[2] && argv[2][0] == '-' && argv[2][1] == '\0')) {
ifs.open(argv[2], ios::in | ios::binary);
if (!ifs) {
ret = 1;
cerr << prog << ": " << argv[2] << ": " << strerror(errno) << endl;
goto end;
}
is = &ifs;
} else {
ss << cin.rdbuf();
if (!ss) {
ret = 1;
cerr << prog << ": failed to read input" << endl;
goto end;
}
is = &ss;
}
is->seekg(0, ios::end);
len = is->tellg();
buf = new char[sz + 1];
while (rd = min(len - count, sz)) {
is->seekg(0 - count - rd, ios::end);
is->read(buf, rd);
count += rd;
char *p = buf + rd, *q;
*p = '\0';
for (;;) {
q = (char *)memrchr(buf, '\n', p - buf);
if (q || count == len) {
if (q) *q = '\0';
if (lines || p - q - 1 > 0 || !q) {
++lines;
cout << lines << ": " << (q ? q + 1 : buf) << line << endl;
line.clear();
if (lines >= maxLines && maxLines != -1) break;
}
if (q) p = q; else break;
} else {
line = string(buf, p - buf) + line;
break;
}
}
}
end:
if (buf) delete[] buf;
return ret;
}
Ce programme utilise des pointeurs et la gestion manuelle de la mémoire sans raison. Le programme pourrait tout aussi bien utiliser std :: vector pour les données dynamiquement allouées et le stockage automatique std :: ifstream au lieu d'un pointeur et d'une allocation dynamique. Cela évite tout nettoyage à la fin, évitant ainsi l'utilisation de goto. Cela évite également une fuite de mémoire. – Tronic
non, vous * avez besoin d'un pointeur * avec 'memrchr'. il * prend seulement un pointeur *. un vecteur serait une couche inutile d'indirection. un pointeur * est nécessaire * pour utiliser cin ici. vous semblez oublier que * les références ne peuvent pas être réajustées * en C++. goto est * nécessaire * pour que l'OP puisse imprimer des messages à la fin de la course. et il n'y a pas besoin de libérer des données juste avant la sortie(). De toute façon, vous êtes obsédé par le sucre syntaxique. – jspcal
Je l'appellerais «préférer le code lisible», pas «obsédé par le sucre syntaxique». Ce code se lit plus comme C que C++ idiomatique. Vous pouvez obtenir un pointeur sur le contenu d'un 'std :: vector', à utiliser avec' memrchr', en appelant 'front()' et en prenant l'adresse. Le pointeur n'est * pas * nécessaire pour utiliser 'cin'; vous pouvez supporter à la fois stdin et noms de fichiers sur la ligne de commande, sans utiliser de pointeurs, en plaçant le code dans une fonction qui prend un paramètre 'istream &' et en lui passant soit std :: cin' ou une instance 'std :: ifstream' nécessaire. – Wyzard
- 1. Fichier mappé en mémoire pour lire la fin du fichier?
- 2. Comment lire un nombre impair de lignes à partir d'un fichier texte en utilisant Java?
- 3. Diviser un gros fichier en fichiers plus petits par le nombre de lignes en C#?
- 4. Comment lire la chaîne souhaitée à partir d'un fichier texte donné ??? en utilisant C#
- 5. Lire un fichier YAML en utilisant un script C
- 6. Fin du fichier (EOF) en C
- 7. Comment lire un fichier en utilisant textscan?
- 8. Comment accéder à un flux audio en utilisant DirectShow.NET C#
- 9. C# Comment ignorer le nombre de lignes pendant la lecture d'un fichier texte en utilisant Stream Reader?
- 10. Comment lire un fichier à partir du dossier d'installation de l'application en utilisant C#?
- 11. Comment lire la chaîne de certificats Pkcs # 7 à partir de fichier/flux en C#?
- 12. Supprimer des lignes en double à partir du fichier texte?
- 13. Comment lire un fichier binaire en C#?
- 14. Lire le flux RSS, fin du lecteur avant la fin des données
- 15. Comment puis-je lire toutes les lignes entre deux lignes dans un fichier, en utilisant Perl?
- 16. Lire des chaînes à partir d'un fichier image en C
- 17. C++ Comment lire des objets avec un décalage donné?
- 18. lire en chiffres en utilisant des chaînes
- 19. comment puis-je lire un fichier binaire en utilisant VBA?
- 20. Comment lire un extrait d'un fichier en utilisant groovy?
- 21. Lire un fichier distant en utilisant Java
- 22. PHP: Comment rechercher un fichier en utilisant des caractères génériques
- 23. comment lire le nombre spécifique de flottants à partir du fichier en python?
- 24. Estimation rapide du nombre de lignes dans un fichier Excel
- 25. C# lire le contenu du fichier et trouver des chaînes
- 26. Comment lire le fichier CSV en utilisant C#
- 27. C++ lire un fichier distant en utilisant boost.
- 28. Lire plusieurs lignes d'un fichier dans une chaîne en C
- 29. Lire des images à partir d'un fichier en C++
- 30. Comment écrire/lire des bits de/vers un flux? (C#)
La bibliothèque standard n'a rien à faire - vous allez avoir à écrire du code. Et pour implémenter le drapeau -f de tail, vous devrez utiliser des trucs non standard. –
Les flux ne sont pas conçus pour cela. Les flux sont destinés à la sérialisation (non-sérialisation des données textuelles). Il serait plus facile de descendre au code C. –