Mam plik tekstowy o nazwie test.txt
Chcę napisać program w C, który może odczytać ten plik i wydrukować zawartość na konsoli (zakładam, że plik zawiera tylko tekst ASCII).
Nie wiem, jak uzyskać rozmiar mojej zmiennej łańcuchowej. Lubię to:
char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
while (fscanf(file, "%s", str)!=EOF)
printf("%s",str);
fclose(file);
}
Rozmiar 999
nie działa, ponieważ ciąg zwracany przez fscanf
może być większy. Jak mogę to rozwiązać?
źródło
stdout
.c
jest to int, a C gwarantuje, żeEOF
nie jest równe żadnemu poprawnemu znakowi.Jest tu wiele dobrych odpowiedzi na temat czytania tego w kawałkach, pokażę ci tylko małą sztuczkę, która odczytuje całą zawartość na raz do bufora i drukuje ją.
Nie mówię, że to lepsze. Tak nie jest i jak Ricardo czasami bywa źle, ale uważam, że to dobre rozwiązanie w prostych przypadkach.
Posypałem to komentarzami, bo dużo się dzieje.
#include <stdio.h> #include <stdlib.h> char* ReadFile(char *filename) { char *buffer = NULL; int string_size, read_size; FILE *handler = fopen(filename, "r"); if (handler) { // Seek the last byte of the file fseek(handler, 0, SEEK_END); // Offset from the first to the last byte, or in other words, filesize string_size = ftell(handler); // go back to the start of the file rewind(handler); // Allocate a string that can hold it all buffer = (char*) malloc(sizeof(char) * (string_size + 1) ); // Read it all in one operation read_size = fread(buffer, sizeof(char), string_size, handler); // fread doesn't set it so put a \0 in the last position // and buffer is now officially a string buffer[string_size] = '\0'; if (string_size != read_size) { // Something went wrong, throw away the memory and set // the buffer to NULL free(buffer); buffer = NULL; } // Always remember to close the file. fclose(handler); } return buffer; } int main() { char *string = ReadFile("yourfile.txt"); if (string) { puts(string); free(string); } return 0; }
Daj mi znać, czy to przydatne, czy możesz się z niego czegoś nauczyć :)
źródło
buffer[string_size] = '\0';
zamiast tego czytaćstring_size+1
? Afaik, rzeczywisty ciąg przechodzi od0
do,string_size-1
a\0
znak musi być w tym miejscustring_size
, prawda?ftell
ifseek
do znalezienia rozmiaru pliku jest niebezpieczne: securecoding.cert.org/confluence/display/seccode/ ...fclose(handle)
calloc(2)
zamiastmalloc(1)
pomijać konieczność ustawiania terminatora zerowego.Zamiast tego po prostu wydrukuj znaki bezpośrednio na konsoli, ponieważ plik tekstowy może być bardzo duży i może wymagać dużo pamięci.
#include <stdio.h> #include <stdlib.h> int main() { FILE *f; char c; f=fopen("test.txt","rt"); while((c=fgetc(f))!=EOF){ printf("%c",c); } fclose(f); return 0; }
źródło
Użyj "read ()" zamiast fscanf:
ssize_t read(int fildes, void *buf, size_t nbyte);
Oto przykład:
http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html
Część robocza z tego przykładu:
f=open(argv[1],O_RDONLY); while ((n=read(f,l,80)) > 0) write(1,l,n);
Alternatywnym podejściem jest użycie
getc
/putc
do odczytu / zapisu 1 znaku na raz. Dużo mniej wydajne. Dobry przykład: http://www.eskimo.com/~scs/cclass/notes/sx13.htmlźródło
read
pozwoli ci przeczytać określoną liczbę znaków. Wczytaj tyle, aby wypełnić bufor, a następnie zrzuć bufor na ekran, wyczyść go i powtarzaj, aż dojdziesz do końca pliku.Przychodzą mi do głowy dwa podejścia.
Po pierwsze, nie używaj
scanf
. Użyjfgets()
which, który przyjmuje parametr do określenia rozmiaru buforu i pozostawia nienaruszone znaki nowej linii. Prosta pętla nad plikiem, który drukuje zawartość bufora, powinna naturalnie skopiować plik w stanie nienaruszonym.Po drugie, użyj
fread()
lub wspólnego idiomu C zfgetc()
. Przetwarzałyby plik w kawałkach o stałym rozmiarze lub pojedynczym znaku na raz.Jeśli musisz przetworzyć plik na ciągach rozdzielonych spacjami, użyj albo
fgets
albo,fread
aby odczytać plik i coś w rodzajustrtok
do podzielenia buforu na białe znaki. Nie zapomnij obsłużyć przejścia z jednego bufora do drugiego, ponieważ łańcuchy docelowe prawdopodobnie obejmują granicę bufora.Jeśli istnieje wymóg zewnętrzny, którego należy użyć
scanf
do wykonania odczytu, ogranicz długość ciągu, który może odczytać, za pomocą pola precyzji w specyfikatorze formatu. W twoim przypadku z 999-bajtowym buforem powiedz,scanf("%998s", str);
który zapisze maksymalnie 998 znaków w buforze, pozostawiając miejsce na terminator nul. Jeśli dozwolone są pojedyncze ciągi dłuższe niż twój bufor, musisz przetworzyć je na dwie części. Jeśli nie, możesz uprzejmie powiedzieć użytkownikowi o błędzie bez tworzenia luki w zabezpieczeniach związanej z przepełnieniem bufora.Niezależnie od tego, zawsze sprawdzaj poprawność zwracanych wartości i zastanów się, jak radzić sobie ze złymi, złośliwymi lub po prostu źle sformułowanymi danymi wejściowymi.
źródło
Możesz użyć
fgets
i ograniczyć rozmiar odczytywanego ciągu.char *fgets(char *str, int num, FILE *stream);
Możesz zmienić
while
kod w swoim kodzie na:while (fgets(str, 100, file)) /* printf("%s", str) */;
źródło
Możesz odczytać cały plik z dynamiczną alokacją pamięci, ale nie jest to dobry pomysł, ponieważ jeśli plik jest zbyt duży, możesz mieć problemy z pamięcią.
Więc lepiej przeczytaj krótkie fragmenty pliku i wydrukuj go.
#include <stdio.h> #define BLOCK 1000 int main() { FILE *f=fopen("teste.txt","r"); int size; char buffer[BLOCK]; // ... while((size=fread(buffer,BLOCK,sizeof(char),f)>0) fwrite(buffer,size,sizeof(char),stdout); fclose(f); // ... return 0; }
źródło