• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

odczyt i zapis - kilka metod

Object Storage Arubacloud
0 głosów
520 wizyt
pytanie zadane 15 maja 2016 w C i C++ przez Evelek Nałogowiec (28,960 p.)

Czy te metody na odczyt i zapis pliku tekstowego są sobie równoważne, a różnica polega tylko w zapisie?

To pierwsza metoda:

ifstream input("wejscie.txt");
ofstream output("wyjscie.txt", ios::app);

To druga metoda:

plik.open("wejscie.txt", ios::in);
plik.open("wyjscie.txt", ios::out | ios::app);

I czy w drugiej metodzie wystarczy dopisać fstream aby działało zarówno odczytywanie pliku jak i zapisywanie do niego?

 

2 odpowiedzi

+1 głos
odpowiedź 15 maja 2016 przez draghan VIP (106,230 p.)
edycja 15 maja 2016 przez draghan
 
Najlepsza

Nie ma jednej, uniwersalnej metody. Strumienie można otwierać na kilka sposobów - i dobrze.

Podawanie parametrów pliku w konstruktorze sprzyja zasadzie RAII i ja tak zazwyczaj piszę. Przede wszystkim dlatego, że jest to czytelne: tworzę obiekt strumienia i już przy jego definicji widać, do czego konkretnie się on odnosi. No i nie wywołuję metody open(), co oszczędza trochę procesora.

Otwieranie za pomocą metody open() stosuje się przeważnie wtedy, gdy uprzednio się strumień zamknęło. Tworzysz jeden obiekt strumienia, otwierasz jakiś plik, wykonujesz operacje, zamykasz go, potem otwierasz inny plik przy pomocy tego samego strumienia.

Co do trybu otwarcia: przy strumieniach specjalizowanych tylko dla wejścia lub tylko dla wyjścia (np. ifstream, ofstream), nie trzeba jako trybu podawać ios::in czy odpowiednio ios::out - to jest domyślny tryb pracy tych strumieni.

Jeśli chcesz strumień zarówno do zapisu, jak i odczytu, piszesz:

#include <fstream>

int main()
{
    std::fstream file("file.txt", std::ios::in | std::ios::out);
    if(file.good())
    {
        int x;
        file >> x;
        file << " " << x + 20;
    }
    return 0;
} 

 

Niektóre komentarze do tej odpowiedzi nawiązują do: http://forum.pasja-informatyki.pl/140767/odczyt-i-zapis-z-pliku-do-pliku?show=140935#c140935

komentarz 15 maja 2016 przez Evelek Nałogowiec (28,960 p.)

Mi to chodzi głównie o przygotowanie do matury, bo zdaje we wtorek z informatyki rozszerzonej.

ifstream input("wejscie.txt");
ofstream output("wyjscie.txt", ios::app);

W tym sposobie nie widzę, w którym miejscu zamykany jest plik. Jak mam przykładowo zadanie: "W pliku "liczby.txt" znajduje się 5000 liczb zapisanych ósemkowo. Sprawdź, ile z nich po zamianie na system dziesiętny jest parzystych i wypisz je". Rozwiązałbym to tak, otwieram najpierw plik "liczby.txt", konwertuje je na system dziesiętny, otwieram plik "po_zamianie.txt" i zapisuje do niego te liczby już w systemie dziesiętnym, zamykam plik "po_zamianie.txt", zamykam plik "liczby.txt". Potem bym otworzył ponownie plik "po_zamianie.txt", wybrał z niego odpowiednim algorytmem wszystkie liczby parzyste, potem otwieram plik "parzyste.txt", wpisuje do niego wszystkie liczby parzyste, zamykam plik "parzyste.txt", zamykam plik "po_zamianie.txt" i mam zadanie z głowy.

Z tym, że nie zawsze mi takie programy działały, dlatego dla mnie bezpieczniejszy sposób, to najpierw w jednym programie zamienić liczby ósemkowe na dziesiętny, a w nowym programie napisać program, który znajdzie mi liczby parzyste.

Gry żadnej nie piszę itd, więc o rzeczy typu pamięć itd. się na maturze nie martwię, nie jest to oceniane. Dlatego wolałbym używać swojego sposobu, najpierw fstream plik, potem open.file("liczby.txt", ios::in), potem otworzyć plik następny do zapisu czyli najpierw zdefiniować trzeba więc fstream plik2, dalej otwieramy  plik.open("po_zamianie.txt" ios::out) po zamianie i wypisaniu wszystkich liczb robię close.plik(); oraz close.plik2();.

W fajnym sposobie podanym przez Ciebie, czyli:

#include <fstream>
#include <streambuf> // do metody "deserowej"
#include <string>
using namespace std;
int main()
{
    ifstream input("we.txt");
    ofstream output("wy.txt");
    string data;

    if(!input.good() || !output.good())
    {
        return 1;
    }
    else
    {
        while(input >> data)
        {
            output << data << "\n";
        }
        return 0;
    }
}

Nie widać, w którym momencie który plik jest otwierany a który zamykany.

komentarz 15 maja 2016 przez draghan VIP (106,230 p.)

Kiedy podajesz wymagane informacje w konstruktorze, następuje próba otwarcia pliku. Pomyśl o tym, jak o krótszym zamienniku:

ifstream input;
input.open("we.txt");

Strumień, otworzony w konstruktorze, niczym się nie różni od tego, otwartego za pomocą metody open(). Tak więc możesz go w dowolnym momencie zamknąć i otworzyć na nowo.

Co do niewidoczności momentu zamknięcia pliku - jest on zamykany w destruktorze obiektu strumienia. A destruktor wywołuje się automatycznie przy niszczeniu obiektu.
Wraz z normalnym opuszczeniem zakresu funkcji, wszystkie obiekty lokalne są niszczone.
W tym konkretnym przypadku są dwa strumienie jako obiekty lokalne funkcji main. Kiedy program opuści funkcję main przez return (czyli stanie się to de facto w momencie zakończenia działania programu), niszczone są wszystkie obiekty z tej funkcji - z wywołaniem ich destruktorów, oczywiście.

PS
Linię #include <streambuf> // do metody "deserowej" możesz usunąć, ona jest potrzebna tylko korzystania z iteratora na bufor strumienia. ;)

komentarz 15 maja 2016 przez draghan VIP (106,230 p.)

Rzuciłem jeszcze okiem na dokumentację i dla strumienia we/wy możesz podać tylko ścieżkę, bez podawania ios::in | ios::out, jako że taki tryb jest domyślny dla tego strumienia.

 

komentarz 15 maja 2016 przez Evelek Nałogowiec (28,960 p.)

Tak, tą linię usunąłem, czytałem twoje komentarze w tym co podesłałeś. :)

Wiedza zostanie, bo wszystko sobie zapisuje i opisuje w folderach, ale na zadaniach maturalnych pozostanę chyba jednak przy plik.open("nazwa.txt", ios::in) i plik.close(); w odpowiednich miejscach.... Jakoś pewniej i bezpieczniej się z tym czuję, bo od zawsze tak robiłem i zawsze wszystko działało.

 

Jedno co zmienię, to zamiast while(!plik.eof()) będę stosował while(input >> data), bo tak jak napisałeś, w tamtej metodzie ostatnia wartość jest dwa razy przepisywana, a to może namieszać w wynikach.

Spodobało mi się też:

if(!input.good() || !output.good())
    {
        return 1;
    }

Stosowałem wcześniej coś podobnego, ale pokazałeś fajny sposób i gdy będzie problem z plikiem to będę widział od razu bo zwróci mi wartość z return, też ciekawy sposób na wykrycie błędu, źle nazwę pliku przepiszę itp. to będę wiedział od razu.

I chyba jeszcze metoda: while(input >> data) jest o tyle lepsza od getline(plik, data), że wczytuje wszystko pokolei oddzielone znakami białymi.

 

komentarz 15 maja 2016 przez draghan VIP (106,230 p.)

Jakoś pewniej i bezpieczniej się z tym czuję, bo od zawsze tak robiłem i zawsze wszystko działało.

Jeśli tylko na maturę, to jasne. Jeśli myślisz o deweloperce w C++, to warto jednak nabrać trochę elastyczności w przyszłości. :)

(...) w tamtej metodzie ostatnia wartość jest dwa razy przepisywana, a to może namieszać w wynikach.

Na 100% namiesza, jeśli pojawi Ci się dodatkowa dana "z powietrza".

Stosowałem wcześniej coś podobnego, ale pokazałeś fajny sposób i gdy będzie problem z plikiem to będę widział od razu bo zwróci mi wartość z return

Można też użyć zwykłego wypisania, nie trzeba od razu zamykać programu. Wszystko zależy od wymagań, od tego czy program może sobie poradzić bez poprawnego otworzenia danego strumienia. Akurat na maturze raczej sobie nie poradzi, bo maturalne programy są czysto wsadowe i bez otwarcia strumienia nie można działać dalej.

I chyba jeszcze metoda: while(input >> data) jest o tyle lepsza od getline(plik, data), że wczytuje wszystko pokolei oddzielone znakami białymi.

Nie można powiedzieć, czy jedna jest lepsza od drugiej. Znów wszystko zależy od wymagań. Dla danych rozdzielonych białymi znakami jest okej. Co zrobisz, gdy dane będziesz miał rozdzielone przecinkami (najprościej - otworzyć Notepadem i zmienić przecinki na spacje funkcją "znajdź i zamień" ;D)? A gdy użyteczne dane również będą zawierały spacje, a separatorem będzie inny znak?

komentarz 15 maja 2016 przez Evelek Nałogowiec (28,960 p.)

Przerobiłem wszystkie zadania z programowania z matur sprzed 5-6 lat, każde zadanie było tak zrobione, że wystarczyło np. właśnie zamienić średnik na spacje i wczytać dane, albo wszystkie dane były wypisane jedno pod drugim.

Co do pozostałych to są jeszcze zadania na arkusz kalkulacyjny, ja sobie wziąłem pakiet Microsoft Office, więc będę się bawił w Excellu i Accessie, chociaż z Accessa zrezygnuje, bo w Excellu można zrobić to samo za pomocą filtru danych itd.

Jeśli Cię jeszcze mogę o coś poprosić, mam zadanie jedno z którym nie potrafię sobie poradzić. Zadanie z tego linku: http://forum.pasja-informatyki.pl/140686/powtarzanie-sie-wyrazu-w-pliku-algorytm

Tutaj jeden użytkownik wysłał kod do programu, jednak nie działa on: http://wklej.org/id/2389848/

Tak jak w poleceniu, chcę sprawdzić, ile razy dany napis powtórzył się w danym pliku a potem wypisać powtarzające się wyrazy. Nie przerabiałem w szkole na lekcjach kontenera map, a jakieś opisy z internetu jak tego używać mi nie pomagają. Mógłbyś rzucić okiem, czy ten kontener map jest dobry w tej sytuacji czy może trzeba użyć czegoś innego? Spotkałem jeszcze jakieś opcje typu string::count czy coś takiego, ale też pierwszy raz to widzę na oczy. Wszystkie dane np. 1000 wyrazów będzie pobierane z pliku tekstowego, potrzeba wypisać te powtarzające się i każdy z nich wypisać tylko raz. Ewentualnie ilość powtórzeń każdego z nich. Typowe zadanie maturalne, ostatnie jakie mi zostało. Sortowania bąbelkowego albo quicksort sobie nie powtarzałem, bo zadań z ich wykorzystaniem nie ma na maturach.

komentarz 15 maja 2016 przez draghan VIP (106,230 p.)
Wieczorem tam zajrzę. ;) Miłego popołudnia. :)
komentarz 15 maja 2016 przez Evelek Nałogowiec (28,960 p.)
Dzięki za dotychczasową pomoc. :) Wzajemnie. :)
0 głosów
odpowiedź 15 maja 2016 przez DragonCoder Nałogowiec (36,500 p.)
Stosowalem osobcie poki co tylko 2 metode. fstream na poczatku dawalem a pozniej plik.open() na koniec close(). A takto podajest tylko << lub>> zalezy czy do pliku czy z pliku.

http://miroslawzelent.pl/kurs-c++/pliki-tekstowe-zapis-odczyt-fstream/

Podobne pytania

0 głosów
2 odpowiedzi 225 wizyt
pytanie zadane 27 grudnia 2018 w C i C++ przez VecsonON Nowicjusz (190 p.)
0 głosów
1 odpowiedź 512 wizyt
pytanie zadane 7 grudnia 2018 w C i C++ przez matiibal Użytkownik (620 p.)
0 głosów
1 odpowiedź 247 wizyt
pytanie zadane 3 listopada 2018 w C i C++ przez gorgonkowa Obywatel (1,810 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...