La lecture de l'intégralité du contenu d'un fichier texte - C
Je suis en train de lire tout le contenu d'un fichier texte. Voici le code que j'ai écrit.
#include <stdio.h>
#include <stdlib.h>
#define PAGE_SIZE 1024
static char *readcontent(const char *filename)
{
char *fcontent = NULL, c;
int index = 0, pagenum = 1;
FILE *fp;
fp = fopen(filename, "r");
if(fp) {
while((c = getc(fp)) != EOF) {
if(!fcontent || index == PAGE_SIZE) {
fcontent = (char*) realloc(fcontent, PAGE_SIZE * pagenum + 1);
++pagenum;
}
fcontent[index++] = c;
}
fcontent[index] = '#include <stdio.h>
#include <stdlib.h>
#define PAGE_SIZE 1024
static char *readcontent(const char *filename)
{
char *fcontent = NULL, c;
int index = 0, pagenum = 1;
FILE *fp;
fp = fopen(filename, "r");
if(fp) {
while((c = getc(fp)) != EOF) {
if(!fcontent || index == PAGE_SIZE) {
fcontent = (char*) realloc(fcontent, PAGE_SIZE * pagenum + 1);
++pagenum;
}
fcontent[index++] = c;
}
fcontent[index] = '\0';
fclose(fp);
}
return fcontent;
}
static void freecontent(char *content)
{
if(content) {
free(content);
content = NULL;
}
}
';
fclose(fp);
}
return fcontent;
}
static void freecontent(char *content)
{
if(content) {
free(content);
content = NULL;
}
}
C'est l'utilisation
int main(int argc, char **argv)
{
char *content;
content = readcontent("filename.txt");
printf("File content : %s\n", content);
fflush(stdout);
freecontent(content);
return 0;
}
Depuis que je suis novice en C, je me demande si ce code est parfait? Voyez-vous des problèmes ou des améliorations?
Compilateur utilisé : GCC. Mais ce code est prévu pour être multi-plateforme.
Toute aide serait appréciée.
Modifier
Voici le code mis à jour avec fread
et ftell
.
static char *readcontent(const char *filename)
{
char *fcontent = NULL;
int fsize = 0;
FILE *fp;
fp = fopen(filename, "r");
if(fp) {
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
fcontent = (char*) malloc(sizeof(char) * fsize);
fread(fcontent, 1, fsize, fp);
fclose(fp);
}
return fcontent;
}
Je me demande ce que sera la relative complexité de cette fonction?
je ne pense pas qu'utiliser que comme un nom de fichier, vous obtiendrez beaucoup d'éloges à l'
ahh.. Désolé. J'ai été le tester et j'ai oublié de l'enlever. Extrêmement désolé.
Je pense qu'en général, vous devriez essayer de travailler en fixe morceaux; dans ce cas, vous serait de la lecture dans PAGE_SIZE octets à la fois (ou moins si c'est le dernier morceau) et de l'impression de chaque morceau de fil de la lecture.
Savez-vous ce que votre code si vous n'avez pas l'autorisation de lecture pour "filename.txt"? Est-ce que vous voulez qu'il fasse?
Vous devriez faire
ahh.. Désolé. J'ai été le tester et j'ai oublié de l'enlever. Extrêmement désolé.
Je pense qu'en général, vous devriez essayer de travailler en fixe morceaux; dans ce cas, vous serait de la lecture dans PAGE_SIZE octets à la fois (ou moins si c'est le dernier morceau) et de l'impression de chaque morceau de fil de la lecture.
Savez-vous ce que votre code si vous n'avez pas l'autorisation de lecture pour "filename.txt"? Est-ce que vous voulez qu'il fasse?
Vous devriez faire
c
un int
. ([f|]getc()
retourne int)OriginalL'auteur Navaneeth K N | 2010-08-01
Vous devez vous connecter pour publier un commentaire.
Vous devriez essayer de regarder dans les fonctions
fsize
(Sur fsize, voir mise à jour ci-dessous) etfread
. Ce pourrait être une grande amélioration de la performance.Utilisation
fsize
pour obtenir la taille du fichier en cours de lecture. Utiliser ce format pour faire une alloc de la mémoire. (Sur fsize, voir mise à jour ci-dessous. L'idée d'obtenir la taille du fichier et de faire une alloc est toujours le même).Utilisation
fread
de faire bloquer la lecture du fichier. C'est beaucoup plus rapide que le simple charecter de la lecture du fichier.Quelque chose comme ceci:
Mise à jour
Pas sûr que fsize est multi plate-forme, mais vous pouvez utiliser cette méthode pour obtenir la taille du fichier:
fsize
, mais ne pouvait pas en trouver un. Est-ce une plate-forme indépendante de la fonction? Commentfsize
peut dire que la taille du fichier sans avoir à lire tout le fichier?Juste mis à jour ma réponse avec un remplacement de fsize 🙂
fsize
dirait que c'est spécifique à Windows.stat(2)
est l'équivalent UNIX.J'ai mis à jour le code avec vos modifications.
N'utilisez pas de
stat
à cette fin. Si le "fichier" n'est pas un fichier normal, mais quelque chose d'autre (peut-être une partition de disque dur), vous n'obtiendrez pas la taille. Toujours utiliser la recherche à la fin de la méthode pour la détermination de la taille. Si vous avez l'intention de prendre en charge la lecture de non-adressable sources (comme une pipe ou douille), alors vous devriez sans doute aussi un soutien supplémentaire de la-realloc approche siftell
retourne -1.OriginalL'auteur Martin Ingvar Kofoed Jensen
Souvent, les gens
realloc
à deux fois la taille existante pour obtenir de l'amorti de la constante de temps au lieu de linéaire. Cela rend le tampon, pas plus que deux fois plus grande, ce qui est généralement bon, et vous avez la possibilité de réaffecter vers le bas à la taille correcte après que vous avez terminé.Mais encore mieux, c'est à
stat(2)
pour la taille du fichier et d'allouer une fois (avec une chambre supplémentaire si la taille du fichier est volatile).Aussi, pourquoi vous n'avez pas
fgets(3)
au lieu de lire caractère par caractère, ou, encore mieux,mmap(2)
l'ensemble de la chose (ou le morceau s'il est trop volumineux pour la mémoire).OriginalL'auteur Wang
Il est probablement plus lent et certainement plus complexe que:
qui fait la même chose que votre code.
OriginalL'auteur msw
C'est à partir d'une lecture rapide, j'ai du raté quelques questions.
D'abord,
a = realloc(a, ...);
est faux. Sirealloc()
échoue, elle renvoieNULL
, mais ne les libère pas la mémoire d'origine. Puisque vous réaffecter àa
, la mémoire d'origine est perdu (c'est à dire, c'est une fuite de mémoire). La bonne façon de faire c'est le faire:tmp = realloc(a, ...); if (tmp) a = tmp;
etc.Seconde, sur la détermination de la taille de fichier à l'aide de
fseek(fp, 0, SEEK_END);
, notez que cela peut ou peut ne pas fonctionner. Si le fichier n'est pas en accès aléatoire (commestdin
), vous ne serez pas en mesure de revenir au début de la lire. Aussi,fseek()
suivie parftell()
ne peut pas donner un résultat significatif pour les fichiers binaires. Et pour les fichiers texte, il ne peut pas vous donner le bon nombre de caractères qui peuvent être lus. Il y a quelques informations utiles sur ce sujet surcomp.lang.c
FAQ question 19.2.Aussi, dans votre code, vous n'avez pas défini
index
à 0 quand elle est égale àPAGESIZE
, donc, si votre fichier de longueur est supérieure à2*PAGESIZE
, vous permettra de remplacer le tampon.Votre
freecontent()
fonction:est inutile. Il définit uniquement une copie de
content
àNULL
. C'est comme si vous avez écrit une fonctionsetzero
comme ceci:Une bien meilleure idée est de garder une trace de la mémoire vous-même et non quelque chose de plus ou de moins que nécessaire.
Vous ne lancez pas la valeur de retour de
malloc()
ourealloc()
en C, depuis unvoid *
est implicitement converti en n'importe quel autre objet de type pointeur dans C.Espère que ça aide.
stdin
est adressable si elle se réfère à un seekable fichier. Ce n'est pas adressable si c'est un dispositif interactif, pipe, etc.fseek
/ftell
fiable sur des fichiers binaires sur n'importe quel système raisonnable. Oui le C standard grands-pères, dans les anciennes implémentations où les fichiers binaires peuvent avoir aléatoire de fuite zéro octets, mais c'est en 2010, et tous les vrais systèmes d'aujourd'hui ont de vrais fichiers binaires. En mode texte ne devraient tout simplement pas être utilisé en raison d'imprévisible et de comportement incorrect. Simplement enlever la\r
'vous-même.Sur mon Mac,
fseek(stdin, 0, SEEK_END)
réussit,ftell()
renvoie la valeur 0, et puis je suis capable de lire, comme beaucoup de personnages destdin
que je veux. Sur linux,fseek(stdin, 0, SEEK_END);
résultats dansIllegal seek
(le même programme). Je préfère unrealloc()
approche fondée sur parce que je n'aurez pas à traiter avec des choses comme le décapage\r
moi-même, et cela fonctionne pour les non-adressable fichiers trop.Sauf si il y a une raison pour laquelle vous avez besoin de tout le fichier en mémoire, vous devriez probablement faire de msw réponse, qui n'a pas de cas d'insuffisance et facilement prouvable exactitude. BTW, si vous voulez bande de
\r
(par exemple à partir de Windows fichiers texte) que vous aurez à faire vous-même de toute façon. Seulement Windows et de l'héritage des Mac (pré-OSX) ont "mode texte" les opérations de fichier qui déforme les données. POSIX nécessite en mode texte se comportent de manière identique à la mode binaire, et il n'sur OSX, Linux, etc.Merci. Vous avez un point très valable ici. Je comprends l'aide de ftell() et fseek() pour trouver la taille du fichier n'est pas dans le bon sens. securecoding.cert.org/confluence/display/seccode/... explique que. Donc, vous dites qu'il faut utiliser le code que j'ai d'abord avec les modifications suggérées par vous?
bien sûr, si le but est d'imprimer le fichier, on n'a pas besoin de code compliqué.
while ((c = getchar()) != EOF)
ouwhile ((nread = fread(buf, 1, sizeof buf, fp) > 0)
à la fois plus facile et plus simple :-). Une info intéressante à propos de l'exigence dans POSIX. Je ne le savais pas merci!OriginalL'auteur Alok Singhal
Un problème, je peux le voir ici est variable
index
qui est non décroissante. Donc, la conditionif(!fcontent || index == PAGE_SIZE)
sera vrai qu'une seule fois. Donc, je pense que devrait être commeindex%PAGE_SIZE == 0
au lieu deindex == PAGE_SIZE
.OriginalL'auteur sudish
Sur les systèmes POSIX (e.g linux), vous pouvez obtenir le même effet avec l'appel système
mmap
que les cartes de tous vos fichiers dans la mémoire. Il dispose d'une option de carte que fichier copie sur écriture, donc vous devez remplacer votre fichier si vous modifiez la mémoire tampon.Ce serait normalement être beaucoup plus efficace, puisque vous laisser autant que vous pouvez pour le système. Pas besoin de faire
realloc
ou similaire.En particulier, si vous êtes seulement de la lecture et de plusieurs processus qui dans le même temps, il n'y aurait qu'une seule copie dans la mémoire de l'ensemble du système.
une référence au fichier du disque dur? assurer que tous les
mmap
fait que c'est l'idée de celui-ci. Ce que je voulais dire, c'est que le système peut supporter toutes les pages que vous n'avez pas de changement dans sa cache de la page et de partager ce cache entre les processus. Cela est vrai pour les deux situations: (1) aussi longtemps que vous le carte les choses en lecture seule ou (2) si vous utilisez une copie sur écriture et vous ne modifiez pas le contenu. Donc, en général, si vous pensez que vous avez besoin d'un accès aléatoire à l'ensemble du contenu d'un fichier,mmap
est presque toujours la meilleure stratégie.fread
et les variantes doivent être limitées au cas où vous avez seulement besoin d'un accès partiel pour le fichier à un moment donné.OriginalL'auteur Jens Gustedt