Odczyt z pliku

0

mam dwa dziwne problemy z programem. Szukałem w różnych miejscach, ale jakoś nie było odpowiedni na moje pytanie.
Windows 7 64 bitowy, mam uprawnienia administratora
Chciałem napisać prosty program. Wypełnia plik 100000 różnymi alfabetycznymi znakami (zapisuje do slowa.txt) a następnie posortowane zapisuje do posrotowane.txt

problemy

  1. nie wiem czemu, ale w StworzPlik musiałem na sztywno podać ścieżki i stworzyć pliki (inaczej ich nie tworzył więc nie miał na czym pracować)
  2. program nie działa jak powinien. Coś się spieprzyło z losowaniem do slowa.txt (stąd w kodzie są stałe typu i<100000) i nie chce mi tego posortować.

jeżeli się da lepiej to prosiłbym o wskazówki :)

edit. jeszcze zapomniałem dodać. Zauważyłem ze plik nie może otwierać dwóch plików tekstowych. Ale jak za komentowałem jeden a później drugi to nadal nie działał jak powinien (w ogółe cout nie zadziałał [nic nie wyświetlił])

main.cpp

#include "PlikiOperacje.h"
int main ()
{
    std::fstream pliczek, wynikowy;
    PlikiOperacje *ploper = new PlikiOperacje();
    if(ploper->StworzPlik(pliczek)){
      ploper->Wypelnij(pliczek);
      ploper->Wczytaj(pliczek);
      ploper->Posortuj(0,100000);
    }
    if(ploper->StworzPlik(wynikowy))
    {
        ploper->Zapisz(wynikowy);

    }

    ploper->ZamknijPlik(pliczek);
    ploper->ZamknijPlik(wynikowy);
    delete ploper;
    return 0;
}

PlikiOperacje.h

 
#ifndef PLIKIOPERACJE_H_INCLUDED
#define PLIKIOPERACJE_H_INCLUDED
#include <fstream>
#include <string>
using std::fstream;
using std::string;
class PlikiOperacje
{
public:
  PlikiOperacje();
  bool StworzPlik(fstream &plik);
  bool Wypelnij(fstream &plik);
  bool Wczytaj(fstream &plik);
  bool Posortuj(int lewy,int prawy);
  bool ZamknijPlik(fstream &plik);
  bool Zapisz(fstream &plik);

private:
  fstream _plik;
  string slowa[100000];
  string linia;

};


#endif // PLIKIOPERACJE_H_INCLUDED

PlikiOperacje.cpp

 
#include <iostream>
#include <fstream>
#include "PlikiOperacje.h"
#include <stdlib.h>
#include <time.h>
#include <string.h>

using std::fstream;
using std::cout;
using std::cin;
using std::ios;
using std::string;

PlikiOperacje::PlikiOperacje()
{
}


bool PlikiOperacje::Wypelnij(fstream &plik)
{
  srand ( time(NULL) );

  for (int i = 0 ; i < 100000 ; i++){
    int doilu = rand() % 10 + 1;
    for (int j = 0 ; j < doilu ; j++){
      int ktory = rand() % 26 + 97;
      plik << char(ktory);
    }
    plik << "\n";
  }

return true;
}


bool PlikiOperacje::Wczytaj(fstream &plik)
{
  int licznik = 0;
  while (true){
    plik >> slowa[licznik++];
    if (!plik.eof())
      break;
    if(licznik > 100000)
      break;
  }
  cout << slowa[0] << slowa[99999];
return true;
}


bool PlikiOperacje::Posortuj(int lewy, int prawy)
{
  int i = lewy, j = prawy;
    string tmp;
    string pivot = slowa[(lewy + prawy) / 2];
    cout << pivot;
    while (i <= j) {
      while (strcmp(slowa[i].c_str(),pivot.c_str())<0)
        i++;
      while (strcmp(slowa[j].c_str(),pivot.c_str())>0)
        j--;
      if (i <= j) {
        tmp = slowa[i];
        slowa[i] = slowa[j];
        slowa[j] = tmp;
        i++;
        j--;
      }
    }

    if (lewy < j)
      Posortuj(lewy, j);
    if (i < prawy)
      Posortuj(i, prawy);

  cout << slowa[0] << slowa [50000] << slowa [99999];
  return true;
}

bool PlikiOperacje::StworzPlik(fstream &plik)
{
  char nazwapliku[200] = "D:\\Bibloteczka\\kotek\\pliki\\slowa.txt";
 // cout << "Podaj nazwe pliku";
 // cin >> nazwapliku;
  if(!plik)
    return false;

  plik.open("D:\\Bibloteczka\\kotek\\pliki\\slowa.txt", ios::in | ios::out );
  plik.open("D:\\Bibloteczka\\kotek\\pliki\\posrotowane.txt", ios::in | ios::out );

  return true;
}

bool PlikiOperacje::ZamknijPlik(fstream &plik)
{

  plik.close();
  return true;
}
bool PlikiOperacje::Zapisz(fstream &plik)
{
  for (int i = 0 ; i < 100000 ; i++){
    plik << slowa[i];
    plik << "\n";
  }

}
0
fasadin napisał(a):

... (zapisuje do slowa.txt) a następnie posortowane zapisuje do posrotowane.txt

Nie, zawsze otwierasz tylko i wyłącznie jeden plik - posrotowane.txt

0

tak, pozniej dopiero zauważyłem ten błąd (stąd mój edit). Jeżeli zakomentuje linijkę z posortowane.txt (albo ogólnie wszystko co jest związane z sortowaniem) to w funkcji

bool PlikiOperacje::Wczytaj(fstream &plik)

linijka

cout << slowa[0] << slowa[99999];

nic nie pokazuję

1

A niby jak ma pokazywać, wskażnik pliku jest na końcu bo dopiero co zapisano.
Próbujesz z tego miejsca czytać, to jasne że nić nie wychodzi.
Zamknij i otwórz plik ponownie lub zrób plik.seekg(0,ios::beg);

0

main.h

 #include "PlikiOperacje.h"
int main ()
{
    std::fstream pliczek, wynikowy;
    PlikiOperacje *ploper = new PlikiOperacje();
    if(ploper->StworzPlik(pliczek)){
      ploper->Wypelnij(pliczek);
      ploper->Wczytaj(pliczek);
     // ploper->Posortuj(0,100000);
    }
    //if(ploper->StworzPlik(wynikowy))
   // {
    //    ploper->Zapisz(wynikowy);

    //}

    ploper->ZamknijPlik(pliczek);
   // ploper->ZamknijPlik(wynikowy);
    delete ploper;
    return 0;
}

a funkcja wygląda tak

 bool PlikiOperacje::Wczytaj(fstream &plik)
{
  plik.seekg(0,ios::beg);
  int licznik = 0;
  while (true){
    plik >> slowa[licznik++];
    if (plik.eof())
      break;
    if (licznik == 100000)
      break;
  }
  cout << slowa[0]<<std::endl << slowa[99999];
return true;
}

pytanie jest takie, co trzeba zrobić zeby sztucznego wyjscia z petli sie pozbyc (chodzi o licznik == 100000)
czy probuje
if (plik.eof())
czy
if (!plik.eof())
to i tak jest źle (nie przerywa po prostu tej petli, lub przerywa od razu)

linijka z seekg pomogła :)

0
int licznik = 0;
while (plik>>slowa[licznik++]) {}
0

niestety nie wiem czemu, ale program się zawiesza przy tej petli
Teraz ogólnie program uruchomiłem (muszę go i tak przerobić całkowicie bo jest napisany po syfiastemu, ale przynajmniej wiem na co mam zwrócić uwagę), ale co dziwnego to slowa.txt generują się za każdym razem (cały plik na nowo), ale posortowane.txt stworzy się tylko raz, jak jest pusty. Później już tego pliku nie nadpisuję

0

To nie jest możliwe, pokaż kod.

0

plikioperacje.cpp

#include <iostream>
#include <fstream>
#include "PlikiOperacje.h"
#include <stdlib.h>
#include <time.h>
#include <string.h>

using std::fstream;
using std::cout;
using std::cin;
using std::ios;
using std::string;

PlikiOperacje::PlikiOperacje()
{
}


bool PlikiOperacje::Wypelnij(fstream &plik)
{
  srand ( time(NULL) );

  for (int i = 0 ; i < 100000 ; i++){
    int doilu = rand() % 10 + 1;
    for (int j = 0 ; j < doilu ; j++){
      int ktory = rand() % 26 + 97;
      plik << char(ktory);
    }
    plik << "\n";
  }

return true;
}


bool PlikiOperacje::Wczytaj(fstream &plik)
{
  plik.seekg(0,ios::beg);
  int licznik = 0;
  while (plik>>slowa[licznik++]) {}
//  while (true){
//    plik >> slowa[licznik++];
//    if (plik.eof())
//      break;
//    if (licznik == 100000)
//      break;
//  }
//  cout << slowa[0]<<std::endl << slowa[99999];
return true;
}


bool PlikiOperacje::Posortuj(int lewy, int prawy)
{
  int i = lewy, j = prawy;
    string tmp;
    string pivot = slowa[(lewy + prawy) / 2];
    //cout << pivot;
    while (i <= j) {
      while (strcmp(slowa[i].c_str(),pivot.c_str())<0)
        i++;
      while (strcmp(slowa[j].c_str(),pivot.c_str())>0)
        j--;
      if (i <= j) {
        tmp = slowa[i];
        slowa[i] = slowa[j];
        slowa[j] = tmp;
        i++;
        j--;
      }
    }

    if (lewy < j)
      Posortuj(lewy, j);
    if (i < prawy)
      Posortuj(i, prawy);

  //cout << slowa[0] << slowa [50000] << slowa [99999];
  return true;
}

bool PlikiOperacje::StworzPlik(fstream &plik, int tryb)
{
  if (tryb == 1){
    plik.open("D:\\Bibloteczka\\kotek\\pliki\\posrotowane.txt", ios::in | ios::out );
    return true;
  }

  char nazwapliku[200] = "D:\\Bibloteczka\\kotek\\pliki\\slowa.txt";
  //cout << "Podaj nazwe pliku";
  //cin >> nazwapliku;
  if(!plik)
    return false;

  plik.open("D:\\Bibloteczka\\kotek\\pliki\\slowa.txt", ios::in | ios::out );
  //plik.open("D:\\Bibloteczka\\kotek\\pliki\\posrotowane.txt", ios::in | ios::out );

  return true;
}

bool PlikiOperacje::ZamknijPlik(fstream &plik)
{

  plik.close();
  return true;
}
bool PlikiOperacje::Zapisz(fstream &plik)
{
  plik.seekg(0,ios::beg);
  for (int i = 0 ; i < 100000 ; i++){
    plik << slowa[i];
    plik << "\n";
  }

}
 

main.cpp

 #include "PlikiOperacje.h"
int main ()
{
    std::fstream pliczek, wynikowy;
    PlikiOperacje *ploper = new PlikiOperacje();
    if(ploper->StworzPlik(pliczek)){
      ploper->Wypelnij(pliczek);
      ploper->Wczytaj(pliczek);
      ploper->Posortuj(0,100000);
    }
    if(ploper->StworzPlik(wynikowy,1))
    {
        ploper->Zapisz(wynikowy);

    }

    ploper->ZamknijPlik(pliczek);
    ploper->ZamknijPlik(wynikowy);
    delete ploper;
    return 0;
}
0

Człowiek uczy się na własnych błędach, mądry człowiek uczy się na cudzych błędach. Mądrę słowa, ale nie uwzględniają ciebie. Przecież już ci tłumaczyłem przy poprzednim problemie. Albo zamykasz i otwierasz albo ...

0

ale w tej funkcji jest przecież otwarty tylko jeden plik. W dodatku zakomentowany kod działa

edit
pamietam jeszcze ze jak zaczalem robic tylko zapis do slowa.txt (istnial tylko jeden plik) to z eof() tez mialem problemy

1

Zmień może main'a na taki:

#include "PlikiOperacje.h"

int main ()
  {
   PlikiOperacje ploper;

   ploper.Losuj("src.txt"); // tworzy plik jeżeli niema 
   ploper.Wczytaj("src.txt"); // wczytuje z pliku, rozmiar tablicy ma zapmiętać
    ploper.Sortuj(); // sortuje
   ploper.Zapisz("dst.txt");
   return 0;
  }

I dostosuj resztę, otwieraj plik i zamykaj wewnątrz metody. Wtedy automagicznie znikną twoje problemy z plikami.
Masz problemy bo:

  1. Po zapisie pliku aby go odczytać tym samym strumieniem trzeba użyć seekg() lub czytać nowym strumieniem.
  2. Po odczycie pliku aby ponownie nadpisać trzeba użyć seekp() lub pisać nowym strumieniem;
  3. Jeżeli odczyt skończył się przez błąd lub eof, trzeba wyczyścić flagi strumienia clear() przed ponownym jego użyciem.
0

rzeczywiście dużo pomogło przerobienie kodu (choć nadal się zastanawiam czemu nie działał ten while skoro działał tylko na jednym pliku), lecz problem mam z inną rzeczą. Dlaczego nie tworzy mi pliku? Mam prawa administratora (win7) oraz wyłączony tryb ochrony (akceptowania każdorazowo jeżeli trzeba coś zrobić z poziomu admina). Jeżeli wcześniej utworze plik (jak tutaj slowa1.txt) to normalnie mi do tego pliku zapisze. Ale średnio mi się podoba to że muszę ręcznie tworzyć

EDIT.
Czy można posortować słowa szybciej? Pomyślałem żeby zrobić strukturę drzewiastą a później wstawiać do niej przez insertSort ją uzupełniać, ale nie wiem czy będzie to szybsze

main

#include "PlikiOperacje.h"
int main ()
{
    PlikiOperacje ploper;
    ploper.Wypelnij("D:\\Bibloteczka\\kotek\\pliki\\slowa1.txt");
    ploper.Wczytaj("D:\\Bibloteczka\\kotek\\pliki\\slowa1.txt");
    ploper.Posortuj(0,100000);
    ploper.Zapisz("D:\\Bibloteczka\\kotek\\pliki\\posrotowane1.txt");
    return 0;
}

PlikiOperacje.cpp

#include <iostream>
#include <fstream>
#include "PlikiOperacje.h"
#include <stdlib.h>
#include <time.h>
#include <string.h>

using std::fstream;
using std::cout;
using std::cin;
using std::ios;
using std::string;

PlikiOperacje::PlikiOperacje()
{
}


bool PlikiOperacje::Wypelnij(char *napis)
{
  fstream plik;
  plik.open(napis, ios::in | ios::out );
  if(!plik)
    return false;

  srand (time(NULL));

  for (int i = 0 ; i < 100000 ; i++){
    int doilu = rand() % 10 + 1;
    for (int j = 0 ; j < doilu ; j++){
      int ktory = rand() % 26 + 97;
      plik << char(ktory);
    }
    plik << "\n";
  }
  plik.close();
  return true;
}


bool PlikiOperacje::Wczytaj(char *napis)
{
  fstream plik;
  plik.open(napis, ios::in | ios::out );
  if(!plik)
    return false;

  int licznik = 0;
  while (plik>>slowa[licznik++]) {}
  cout << slowa[0]<<std::endl << slowa[99999];
  plik.close();
return true;
}


bool PlikiOperacje::Posortuj(int lewy, int prawy)
{
  int i = lewy, j = prawy;
    string tmp;
    string pivot = slowa[(lewy + prawy) / 2];
    while (i <= j) {
      while (strcmp(slowa[i].c_str(),pivot.c_str())<0)
        i++;
      while (strcmp(slowa[j].c_str(),pivot.c_str())>0)
        j--;
      if (i <= j) {
        tmp = slowa[i];
        slowa[i] = slowa[j];
        slowa[j] = tmp;
        i++;
        j--;
      }
    }

    if (lewy < j)
      Posortuj(lewy, j);
    if (i < prawy)
      Posortuj(i, prawy);
  return true;
}


bool PlikiOperacje::Zapisz(char *napis)
{
  fstream plik;
  plik.open(napis, ios::in | ios::out );
  if(!plik)
    return false;

  for (int i = 0 ; i < 100000 ; i++){
    plik << slowa[i];
    plik << "\n";
  }
  plik.close();
}
 

PlikiOperacje.h

#ifndef PLIKIOPERACJE_H_INCLUDED
#define PLIKIOPERACJE_H_INCLUDED
#include <fstream>
#include <string>
using std::fstream;
using std::string;
class PlikiOperacje
{
public:
  PlikiOperacje();
  bool Wypelnij(char *napis);
  bool Wczytaj(char *napis);
  bool Posortuj(int lewy,int prawy);
  bool Zapisz(char *napis);

private:
  fstream _plik;
  string slowa[100000];
  string linia;

};


#endif // PLIKIOPERACJE_H_INCLUDED
 
0

Otwierasz plik do czytania i pisania, więc pewnie chcesz modyfikować to co istnieje, dla tego nie tworzy nowego.

bool PlikiOperacje::Wypelnij(char *napis)
  {
   ofstream plik(napis, ios::in | ios::out ); // lub fstream plik(napis,ios::out);
   if(!plik) return false;
   srand (time(NULL)); // to lepiej przenieś przynajmniej do konstruktora klasy, lub zupełnie do main'a.
   for(int i=0;i<100000;++i,plik<<endl) for (int j=1+rand()%10 ;j>0;--j) plik <<(char)('a'+rand()%26);
   //plik.close(); plik sam się zamknie po return
   return true;
  }
0

już wszystko jasne :) niepotrzebnie miałem flage ios::in (ofstream z flagą ios::in także nie tworzył pliku, ale jak wykasowałem flagę to voila)
Dziękuje za cierpliwość i wyrozumiałość :) A można wiedzieć czemu formatowanie jest takie?

 if(!plik) return false;

często się z tym spotykam, ale jak debugguje kod (nie zawsze jest return) to ogólnie jakoś zawsze źle mi się takie rzeczy debugguje a chciałbym wiedzieć jaki cel niesie za sobą takie formatowanie (moim zdaniem przejście do następnej linijki może i wydłuża kod, ale po prostu kod jest czytelniejszy)

0

Wg mnie akceptowalne dwa warianty:

if(!plik) return false;

lub:

if(!plik)
  {
   return false;
  }

Ze względu na nieuków którzy czasami muszą rozwijać mój kod. Przy zapisie takim jak dałeś, często potem widzę kwiatki w rodzaju:

if(!plik)
    LogWrite("Nieudane otwarcie pliku");
    return false;

Jeżeli w kodzie przed jego "usprawnieniem" było jak u ciebie to on się tłumaczy: - "Nie zauważyłem!".
A jeżeli w kodzie był jeden z moich wariantów - to koleś nie ma usprawiedliwienia więc mogę czystym sumieniem wywalić z zespołu w trybie natychmiastowym.

0

Ogólnie ja zawsze piszę
if(warunek){
instrukcje
}
więc jak widzę
if(warunek)
instrukcja1;
instrukcja2;

to od razu wiem że coś nie jest tak. Widać to że zamykająca klamra dotyczy konkretnie tego ifa,a skoro jest wcięcie a nie ma zamykającego ifa to ktoś się pomylił. Często także po ifie daje enter żeby odznaczać "segmenty" kodu.
Dlatego mnie zdziwiło trochę ze ktoś się myli gdy są wcięcia.
Dzięki za wyjaśnienie :)

0

Dam ci dobrą radę. Jak zrobisz już ten swój program zapisz go w swoim formatowaniu. Przerób na moje:

if(!plik)
  {
   return false;
  }

czyli zawsze klamerka w osobnym wierszu, klamerka ma wcięcie odnośnie if/while/for/funkcja itp. (u mnie to 2 spacji) to co wewnątrz klamerki ma jeszcze wcięcie odnośnie klamerki ale mniejsze (u mnie 1 spacja) i zapisz ten plik pod inną nazwa. Za miesiąc wydrukuj oba i spójrz na nie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1