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

Problem z zapisem do pliku

Object Storage Arubacloud
0 głosów
331 wizyt
pytanie zadane 14 października 2020 w C i C++ przez magda_19 Gaduła (3,080 p.)

Piszę taki program, który odczytuje plik .txt z danymi osób zapisanymi w oddzielnej linii i ma skonwertować te dane na taki zapis, że jedna osoba i jej dane są w jednej linii. Na przykład:

Stary styl:                                                                                  Nowy styl:

ID: 1                                                                                          1|Magda|ppppppp

Imie: Magda

Nazwisko: ppppppp

Jak na razie plik w nowym stylu się zapisuje, ale jest pusty. Są tylko kreski, czyli tak jakby program wgl nie widział tych danych.

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>

using namespace std;

struct Adresat {
    int idOsoby = 0;
    string imie, nazwisko, nrTel, email, adres;
};

int wczytajOsobyZPlikuWStarymStylu () {
    string liniaTekstuDoOdczytania;
    Adresat pomoc;
    vector <Adresat> adresaci;
    int nrLinii = 1;
    int iloscOsob = 0;

    fstream plikDoOdczytu;
    plikDoOdczytu.open("ksiazka_z_adresami.txt", ios::in);

    if (plikDoOdczytu.good()== true) {
        while (getline(plikDoOdczytu, liniaTekstuDoOdczytania)) {
            switch (nrLinii) {
            case 1:
                pomoc.idOsoby = atoi(liniaTekstuDoOdczytania.c_str());
                break;
            case 2:
                pomoc.imie = liniaTekstuDoOdczytania;
                break;
            case 3:
                pomoc.nazwisko = liniaTekstuDoOdczytania;
                break;
            case 4:
                pomoc.nrTel = liniaTekstuDoOdczytania;
                break;
            case 5:
                pomoc.email = liniaTekstuDoOdczytania;
                break;
            case 6:
                pomoc.adres = liniaTekstuDoOdczytania;
                break;
            }
            if (nrLinii >= 6) {
                nrLinii = 1;
                iloscOsob++;
            } else {
                nrLinii++;
            }
        }
        plikDoOdczytu.close();
    }
    return iloscOsob;
}

int zapiszOsobeWNowymStylu() /*(int iloscOsob) */{
    int iloscOsob;
    wczytajOsobyZPlikuWStarymStylu();
    Adresat pomoc;
    string imie = "", nazwisko = " ", nrTel = " ", email = " ", adres = " ";
    int idAdresata = iloscOsob + 1;
    vector <Adresat> adresaci;

    std::string s = std::to_string(idAdresata);

    pomoc.idOsoby = adresaci.size() + 1;
    pomoc.imie = imie;
    pomoc.nazwisko = nazwisko;
    pomoc.nrTel = nrTel;
    pomoc.email = email;
    pomoc.adres = adres;

    adresaci.push_back(pomoc);
    fstream plikDoZapisu;
    plikDoZapisu.open("ksiazka_ZAdresami_Nowy_Format.txt", ios::out | ios::app);

    if (plikDoZapisu.good() == true) {
        plikDoZapisu << pomoc.idOsoby << "|" << pomoc.imie << "|" << pomoc.nazwisko << "|" << pomoc.nrTel << "|" << pomoc.email << "|" << pomoc.adres << "|" << endl;
        plikDoZapisu.close();
    }
    else {
        cout << "Nie udalo sie otworzyc pliku";
        system("pause");
    }
    cout << "Osoba zostala dodana do ksiazki adresowej w nowym stylu" << endl;
    system("pause");

    iloscOsob++;

    return iloscOsob + 1;
}

//program ma wczytywac w starym stylu, a zapisywac w nowym
string PobierzNazweStaregoPliku (string nazwaStaregoPliku) {
    cout << "Podaj nazwe starego pliku zrodlowego z rozszerzeniem .txt: ";
    cin >> nazwaStaregoPliku;
    if (nazwaStaregoPliku == "ksiazka_z_adresami.txt") {
        return nazwaStaregoPliku;
    }
    else
        cout << "Podany plik nie istnieje!!";
}

void konwertujStaryPlikNaNowy () {
    string staryPlik;
    int iloscOsob;
    PobierzNazweStaregoPliku(staryPlik);
    wczytajOsobyZPlikuWStarymStylu();
    zapiszOsobeWNowymStylu();
}

int main() {
    string nazwaStaregoPliku;
    konwertujStaryPlikNaNowy();

    return 0;
}

 

komentarz 14 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
cout << "Podaj nazwe starego pliku zrodlowego z rozszerzeniem .txt: ";
    cin >> nazwaStaregoPliku;
    if (nazwaStaregoPliku == "ksiazka_z_adresami.txt") {
        return nazwaStaregoPliku;
    }
    else
        cout << "Podany plik nie istnieje!!";

huh?

komentarz 14 października 2020 przez magda_19 Gaduła (3,080 p.)
Sprawdzam czy plik o podanej nazwie istnieje.
komentarz 14 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
Nie sprawdzasz.. Ty sprawdzasz, czy to co wprowadził user równa się "ksiazka_z_adresami.txt", jeśli nie, to wypisujesz, że nie ma takiego pliku (jednak nie sprawdzasz w ogóle czy taki plik jest)
komentarz 14 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
#include <iostream>
#include <filesystem> //kompilator wspierający bodaj c++17 i nowsze

std::string PobierzNazweStaregoPliku() {
	namespace fs = std::filesystem;
	
	std::string nazwaStaregoPliku;
		
	std::cout << "Podaj nazwe starego pliku zrodlowego z rozszerzeniem .txt: ";
    std::cin >> nazwaStaregoPliku;

	while(!fs::exists(nazwaStaregoPliku)){
		std::cout << "Podany plik nie istnieje, podaj nazwe jeszcze raz: ";
		std::cin >> nazwaStaregoPliku;
	}

	return nazwaStaregoPliku;
}


int main(){
	std::cout << PobierzNazweStaregoPliku();
}

O coś takiego Ci chodziło?

1
komentarz 14 października 2020 przez tkz Nałogowiec (42,000 p.)

@magda_19,

#include <fstream>
#include <iostream>
#include <string>

void serializationOfDataInNewStyleWithPipe(const std::string &oldFileName,
                                           const std::string &newFileName)
{
    std::ifstream baseFile(oldFileName);
    std::ofstream outputFile(newFileName);
    std::string line;
    std::string data;
    std::size_t counter{0};
    while (std::getline(baseFile, line))
    {
        if (counter % 3 == 0 && counter != 0)
        {
            outputFile << (data.pop_back(), data) << '\n';
            data.clear();
        }
        auto parsing = [](const std::string &text) {
            constexpr char SEPARATOR = ':';
            if (auto found = text.find(SEPARATOR); found != std::string::npos)
            {
                auto beginWord{(text.begin() + found + 2)};
                return std::string(beginWord, text.end());
            }
            return text;
        }(line);
        constexpr char PIPE_SEPARATOR = '|';
        data += parsing + PIPE_SEPARATOR;
        ++counter;
    }
}

int main()
{
    serializationOfDataInNewStyleWithPipe("base.txt", "out.txt");
}

Może coś takiego, kwestia, czy chcesz działać na plikach, czy na vektorze. 

komentarz 16 października 2020 przez magda_19 Gaduła (3,080 p.)
Wolałabym na wektorze
komentarz 17 października 2020 przez tkz Nałogowiec (42,000 p.)
#include <fstream>
#include <string>
#include <vector>

void serializationOfDataInNewStyleWithPipe(const std::string &oldFileName,
                                           const std::string &newFileName)
{
    std::ifstream baseFile(oldFileName);
    std::ofstream outputFile(newFileName);
    std::string line;
    std::string data;
    std::size_t counter{0};
    while (std::getline(baseFile, line))
    {
        if (counter % 3 == 0 && counter != 0)
        {
            outputFile << (data.pop_back(), data) << '\n';
            data.clear();
        }
        auto parsing = [](const std::string &text) {
            const char SEPARATOR = ':';
            if (auto found = text.find(SEPARATOR); found != std::string::npos)
            {
                auto beginWord{(text.begin() + found + 2)};
                return std::string(beginWord, text.end());
            }
            return text;
        }(line);
        const char PIPE_SEPARATOR = '|';
        data += parsing + PIPE_SEPARATOR;
        ++counter;
    }
}

struct Addressee
{
    int idOsoby = 0;
    std::string imie, nazwisko; //, nrTel, email, adres;
};

void serializationOfDataInNewStyleWithPipe(const std::vector<Addressee> &addressees,
                                           const std::string &newFileName)
{
    std::ofstream outputFile(newFileName);
    for (const auto &[id, name, surName /*, phoneNumber, email, address*/] : addressees)
    {
        const char SEPARATOR = '|';
        outputFile << id << SEPARATOR << name << SEPARATOR << surName << "\n";
    }
}

int main()
{
    auto vectorOfAddressees = std::vector<Addressee>{
        {1, "ala", "kot"}, {2, "ala", "kot"}, {3, "ala", "kot"}, {4, "ala", "kot"}};
    serializationOfDataInNewStyleWithPipe(vectorOfAddressees, "out.txt");
}

Jeżeli będziesz chciała użyć kodu powyżej zwróć uwagę na tryb zapisu do pliku. Użyłem również przeciążenia funkcji, co również należy zmienić. Ponieważ nazwy nie opisują zbyt dokładnie tego co robią funkcję. 

2 odpowiedzi

0 głosów
odpowiedź 14 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
int zapiszOsobeWNowymStylu() /*(int iloscOsob) */{
    int iloscOsob;
    wczytajOsobyZPlikuWStarymStylu();
    Adresat pomoc;
    string imie = "", nazwisko = " ", nrTel = " ", email = " ", adres = " ";
    int idAdresata = iloscOsob + 1;
    vector <Adresat> adresaci;
 
    std::string s = std::to_string(idAdresata);
 
    pomoc.idOsoby = adresaci.size() + 1;
    pomoc.imie = imie;
    pomoc.nazwisko = nazwisko;
    pomoc.nrTel = nrTel;
    pomoc.email = email;
    pomoc.adres = adres;
 
    adresaci.push_back(pomoc);
    fstream plikDoZapisu;
    plikDoZapisu.open("ksiazka_ZAdresami_Nowy_Format.txt", ios::out | ios::app);
 
    if (plikDoZapisu.good() == true) {
        plikDoZapisu << pomoc.idOsoby << "|" << pomoc.imie << "|" << pomoc.nazwisko << "|" << pomoc.nrTel << "|" << pomoc.email << "|" << pomoc.adres << "|" << endl;
        plikDoZapisu.close();
    }
    else {
        cout << "Nie udalo sie otworzyc pliku";
        system("pause");
    }
    cout << "Osoba zostala dodana do ksiazki adresowej w nowym stylu" << endl;
    system("pause");
 
    iloscOsob++;
 
    return iloscOsob + 1;
}

Nic dziwnego, że nic do pliku nie jest zapisywane. W tym kodzie przecież nigdzie nie przekazujesz sobie tego co wczytałaś wcześniej. Masz wyrażenie, jakim jest call do funkcji wczytajOsobyZPlikuWStarymStylu, jednak to co ta funkcja zwraca Ci przepada. Potem tworzysz nową strukturę Adresata, którą wypełniasz pustymi danymi, masz też vector, którego nie używasz, masz generalnie lekki bałagan w tym programie. Btw. idAdresata i wynik funkcji zapiszOsobeWNowymStylu bedą totalnie losowe i (nie)zależne od wieku użytkownika, dnia, godziny, znaku zodiaku najbliższego kota czy fazy księżyca

komentarz 14 października 2020 przez magda_19 Gaduła (3,080 p.)
No właśnie nie wiem jak mogę przekazać to, co jest odczytane.
komentarz 14 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Musisz mieć vector, który będzie dostępny dla obu funkcji. Czyli najlepiej stwórz vector Adresatów, który przekażesz do funkcji wczytajOsobyZPlikuWStarymStylu, tam wczytasz sobie do tego vectora adresatów, następnie przekażesz ten sam vector do funkcji zapiszOsobeWNowymStylu, z którego zapiszesz sobie te osoby/osobę (jedna funkcja mówi o osobach, druga o tylko jednej?) do pliku.

komentarz 16 października 2020 przez magda_19 Gaduła (3,080 p.)

Przekazałam wektor do obu funkcji, ale nadal nie działa.

vector <Adresat> wczytajOsobyZPlikuWStarymStylu (vector <Adresat> &adresaci) {
    string liniaTekstuDoOdczytania;
    Adresat pomoc;
    int nrLinii = 1;
    int iloscOsob = 0;

    fstream plikDoOdczytu;
    plikDoOdczytu.open("ksiazka_z_adresami.txt", ios::in);

    if (plikDoOdczytu.good()== true) {
        while (getline(plikDoOdczytu, liniaTekstuDoOdczytania)) {
            switch (nrLinii) {
            case 1:
                pomoc.idOsoby = atoi(liniaTekstuDoOdczytania.c_str());
                break;
            case 2:
                pomoc.imie = liniaTekstuDoOdczytania;
                break;
            case 3:
                pomoc.nazwisko = liniaTekstuDoOdczytania;
                break;
            case 4:
                pomoc.nrTel = liniaTekstuDoOdczytania;
                break;
            case 5:
                pomoc.email = liniaTekstuDoOdczytania;
                break;
            case 6:
                pomoc.adres = liniaTekstuDoOdczytania;
                break;
            }
            if (nrLinii >= 6) {
                nrLinii = 1;
                iloscOsob++;
            } else {
                nrLinii++;
            }
        }
        plikDoOdczytu.close();
        adresaci.push_back(pomoc);
    }
    return adresaci;
}

vector <Adresat> zapiszOsobeWNowymStylu(vector <Adresat> &adresaci) {
    int iloscOsob;
    wczytajOsobyZPlikuWStarymStylu(adresaci);
    Adresat pomoc;
    string imie = "", nazwisko = " ", nrTel = " ", email = " ", adres = " ";
    int idAdresata = iloscOsob + 1;

    std::string s = std::to_string(idAdresata);

    pomoc.idOsoby = adresaci.size() + 1;
    pomoc.imie = imie;
    pomoc.nazwisko = nazwisko;
    pomoc.nrTel = nrTel;
    pomoc.email = email;
    pomoc.adres = adres;

    adresaci.push_back(pomoc);

    fstream plikDoZapisu;
    plikDoZapisu.open("ksiazka_Z_Adresami_Nowy_Format.txt", ios::out | ios::app);

    if (plikDoZapisu.good() == true) {
        plikDoZapisu << pomoc.idOsoby << "|" << pomoc.imie << "|" << pomoc.nazwisko << "|" << pomoc.nrTel << "|" << pomoc.email << "|" << pomoc.adres << "|" << endl;
        plikDoZapisu.close();
    }
    else {
        cout << "Nie udalo sie otworzyc pliku";
        system("pause");
    }
    cout << "Osoby zostaly dodana do ksiazki adresowej w nowym stylu" << endl;
    system("pause");

    return adresaci;

}

 

0 głosów
odpowiedź 14 października 2020 przez TOWaD Mądrala (5,700 p.)
edycja 14 października 2020 przez TOWaD

jak tylko o przepisanie pliku chodzi to może tak

#include <algorithm>
#include <iostream>
#include <iterator>
#include <fstream>
int main()
{  
    std::string v;
       { 
        std::ifstream is("plik_z_enterami");
        std::getline(is,v,'\0');
        }
    int i = 0;
    int coileenterow = 6;
    std::replace_copy_if(v.begin(), v.end(),
    v.begin(),
                         [&](char n){
                             if(n=='\n' && (++i==coileenterow)){
                                n='\n'+1;i=0;
                            }
                            return n == '\n';},'|');
     { 
        std::ofstream os("plik_z_recordami");
       os<<v<<'\0';
       }
}

 

komentarz 16 października 2020 przez magda_19 Gaduła (3,080 p.)

Spoko kod, dzięki. Mógłbyś mi tylko wytłumaczyć co tutaj się dzieje:

 std::replace_copy_if(v.begin(), v.end(),
    v.begin(),
                         [&](char n){
                             if(n=='\n' && (++i==coileenterow)){
                                n='\n'+1;i=0;
                            }
                            return n == '\n';},'|');
     { 

 

komentarz 17 października 2020 przez tkz Nałogowiec (42,000 p.)

http://www.cplusplus.com/reference/algorithm/replace_copy_if/
Ogólnie kod jest mało czytelny, po części może być to wina formatowania. 

Funkcja std::replace_copy_if kopiuje w zakresie od v.begin() do v.end() w nowe miejsce, które zaczyna się w v.begin(). Jeżeli to:
 

        [&](char n)
        {
            if (n == '\n' && (++i == coileenterow))
            {
                n = '\n' + 1;
                i = 0;
            }
            return n == '\n';
        },

zwróci prawdę, to zamieni obecny element na '|'.

Sama funkcja lambda znajdująca się w std::replace_copy_if przyjmuję char, bo iterujemy po stringu, sprawdza, czy wartość równa się znakowi nowej linii, jeżeli tak, to zwracamy true, by zastąpić \n -> |. 

komentarz 17 października 2020 przez VBService Ekspert (253,340 p.)
komentarz 19 października 2020 przez TOWaD Mądrala (5,700 p.)

@magda_19,   przepraszam za ten potworek, 

ale generalnie wczytuję  znak po znaku z jednego pliku liczę entery i co 6 enter zostawiam a resztę podmieniam na znak "|"

[&] //wychwycenie parametrów zewnętrznych dla funkcji lambda przez referencję
(char n) // przechwycenie wartości iteratora
{
    if (n == '\n' && (++i == coileenterow)) // jak szósty enter to zwróci prawdę...
    {
        n = '\n' + 1;  //(13+1=14) ...i zamieni enter na inny znak ASII i cała funkcja lambda zwróci fałsz
        i = 0;
    }
    return n == '\n'; // jak warunek ('\n'=='\n') prawdziwy to zamienia znak z '|' na '\n'

,ale fakt to nie była najlepsza odpowiedz na pytanie. 

komentarz 19 października 2020 przez magda_19 Gaduła (3,080 p.)
Hej, dzięki za wyjaśnienie.
komentarz 19 października 2020 przez TOWaD Mądrala (5,700 p.)
edycja 22 października 2020 przez TOWaD

trochę nie dokładnie z tą referencją bo "Opusie" piszą referencja to

"lokalne obiekty z bieżącego zakresu"

Ale jak ktoś dużo bardziej oblatany z c++ skomentował moja odpowiedz.

Nie ucz się głupot

i chodzi mi o akurat takie zastosowanie lambdy i STL.

edit: chodzi mi, używanie STL i lambdy do wczytywania pliku znak po znaku i żeby się nie mądrzyć, to tak informacyjnie, ja nie wiem jak programowanie wygląda w praktyce.

a tak bym twój projekt zrobił na zaliczenie 

edit:: taka mała poprawka //może bana nie dostanę za tyle znaków

zEnterami.txt // dla innych danych nie bardzo działa

Grzegorz
Nowak
Miasto
00-001
ulica Binarna 2;
1
Ireneusz
Kowalaki
Miasto
00-001
ulica Oct 8;
2
Ireneusz
Kowalaki
Miasto
00-001
ulica Hex 8;
3
a tu 
niepełne dane

main.cpp

#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <vector>

bool fpf(char &a) {
    if(a!='\n')
        a+=5;
    return 1;
}
bool fmf(char &a) {
    if(a!='\n')
        a-=5;
    return 1;
}
class stF {
    size_t length;
    std::string data;
    char ch=25;
public:
    stF (std::string str):data(str) {};
    bool write(std::ostream & os) {
        if(os) {
            length=data.size();
            std::string::iterator it=data.begin();
            std::copy_if(data.begin(),data.end(),data.begin(),(*fpf));
            os.write((char*)&length,sizeof(length));
            os.write(data.data(),length);
        } else
            return 0;
        return 1;
    }
    bool read(std::istream & is) {
        if (is) {
            length=data.size();
            is.read((char*)&length,sizeof(length));
            is.read(&data[0],length);
            std::copy_if(data.begin(),data.end(),data.begin(),(*fmf));
        } else
            return 0;

        return 1;
    }
    void show() {
        std::cout<<length<<'-'<<data<<std::endl;
    }
};

struct NoPod {
    int id;
    std::string fname;
    std::string lname;
    std::string addres;
    std::string zipCode;
    std::string street;
};

namespace vectorNoPod {
    using vP1=std::vector<NoPod>;
    vP1 v;

    std::stringstream ss;
}

bool plikZEnterami (std::istream & in) {
    NoPod pd;
    if(getline(in,pd.fname)
            && getline(in,pd.lname)
            && getline(in,pd.addres)
            && getline(in,pd.zipCode)
            && getline(in,pd.street)
            && in>>pd.id
      )
        vectorNoPod::v.push_back(pd);

    return (in.get()=='\n') ;
}
void plikbezEnterow (std::ostream & os,NoPod pd) {
    os<<pd.id<<'|'
      << pd.fname<<'|'
      << pd.lname<<'|'
      << pd.addres<<'|'
      << pd.zipCode<<'|'
      << pd.street<<'\n';
    return;
}


int main () {

    {
        std::string nameofinputfile("zEnterami.txt");
        std::ifstream zEinFF (nameofinputfile);
        while (plikZEnterami (zEinFF));
    }


    for (const NoPod &x: vectorNoPod ::v)
        plikbezEnterow (vectorNoPod::ss,x);

    {
        std::string nameofoutputfile("bezEnterów.txt");
        std::ofstream bezEoutFF (nameofoutputfile,std::ios::binary);
        std::ifstream bezEinFF (nameofoutputfile,std::ios::binary);
        stF F(vectorNoPod::ss.str());
        F.write(bezEoutFF);
        std::cout<<"tak wygladaja string (char+5) przed wyslaniem do pliku: \n";
        F.show();
        F.read(bezEinFF);
        std::cout<<"tak wygladaja string (char-5) pobrany z pliku: \n";
        F.show();
    }


    return 0;
}

 

Podobne pytania

0 głosów
0 odpowiedzi 126 wizyt
pytanie zadane 7 lipca 2022 w C i C++ przez tymek112 Obywatel (1,530 p.)
0 głosów
1 odpowiedź 346 wizyt
pytanie zadane 20 września 2020 w C i C++ przez magda_19 Gaduła (3,080 p.)
0 głosów
4 odpowiedzi 227 wizyt
pytanie zadane 9 września 2017 w C i C++ przez fipooo Bywalec (2,880 p.)

92,568 zapytań

141,422 odpowiedzi

319,635 komentarzy

61,956 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!

...