W C, jak powinienem przeczytać plik tekstowy i wydrukować wszystkie ciągi

103

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:

Rozmiar 999nie działa, ponieważ ciąg zwracany przez fscanfmoże być większy. Jak mogę to rozwiązać?

Richard
źródło

Odpowiedzi:

142

Najprostszym sposobem jest przeczytanie znaku i wydrukowanie go zaraz po przeczytaniu:

cjest intpowyżej, ponieważ EOFjest liczbą ujemną i charmoże być zwykły unsigned.

Jeśli chcesz czytać plik w kawałkach, ale bez dynamicznej alokacji pamięci, możesz zrobić:

Druga metoda powyżej polega zasadniczo na tym, jak odczytać plik z dynamicznie przydzieloną tablicą:

Twoja metoda fscanf()with %sas format traci informacje o białych znakach w pliku, więc nie jest to dokładne kopiowanie pliku do stdout.

Alok Singhal
źródło
Możliwe jest odczytanie danych z pliku bez otwierania tego pliku w c / c ++ ??
Sagar Patel
co, jeśli plik tekstowy zawiera wartości całkowite oddzielone przecinkami? niż jaki byłby kod, możesz edytować swoją odpowiedź z tym również.
Mohsin
Powyższe działa dla każdego rodzaju pliku tekstowego. Jeśli chcesz przeanalizować liczby z pliku CSV, to jest inny problem.
Alok Singhal
1
@overexchange Pytanie nie dotyczy linii - chodzi o odczytanie pliku i skopiowanie do niego jego zawartości stdout.
Alok Singhal,
1
@shjeff Plik nie może zawierać znaku EOF. Zauważ, że cjest to int, a C gwarantuje, że EOFnie jest równe żadnemu poprawnemu znakowi.
Alok Singhal
62

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.

Daj mi znać, czy to przydatne, czy możesz się z niego czegoś nauczyć :)

lfzawacki
źródło
2
Nie powinno buffer[string_size] = '\0';zamiast tego czytać string_size+1? Afaik, rzeczywisty ciąg przechodzi od 0do, string_size-1a \0znak musi być w tym miejscu string_size, prawda?
aepsil0n
4
Używanie ftelli fseekdo znalezienia rozmiaru pliku jest niebezpieczne: securecoding.cert.org/confluence/display/seccode/ ...
Joakim
1
Ten kod zawiera wyciek pamięci, nigdy nie zamykasz pliku. Brakujefclose(handle)
Joakim
1
Jest literówka, w której wywołujesz fclose (uchwyt), powinno być fclose (handler)
Eduardo Cobuci
3
Możesz użyć calloc(2)zamiast malloc(1)pomijać konieczność ustawiania terminatora zerowego.
15

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.

Sagar Shah
źródło
6

Użyj "read ()" zamiast fscanf:

OPIS

Funkcja read () podejmuje próbę odczytania nbytebajtów z pliku skojarzonego z deskryptorem otwartego pliku,fildes do bufora wskazywanego przez buf.

Oto przykład:

http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html

Część robocza z tego przykładu:


Alternatywnym podejściem jest użycie getc/ putcdo odczytu / zapisu 1 znaku na raz. Dużo mniej wydajne. Dobry przykład: http://www.eskimo.com/~scs/cclass/notes/sx13.html

DVK
źródło
readpozwoli 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.
bta
1

Przychodzą mi do głowy dwa podejścia.

Po pierwsze, nie używaj scanf. Użyj fgets()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 z fgetc(). 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 fgetsalbo, freadaby 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ć scanfdo 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.

RBerteig
źródło
1

Możesz użyć fgetsi ograniczyć rozmiar odczytywanego ciągu.

Możesz zmienić whilekod w swoim kodzie na:

Edu
źródło
0

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.

rigon
źródło