Program kompresujący RLE - zawiesza się

Odpowiedz Nowy wątek
2011-10-04 10:57
0

Witam,

napisałem prosty program, który ma za zadanie kompresować pliki. Pojawiły się 2 problemy:

  1. Ja obliczyć długość pliku - potrzebne do pętli (dlatego przypisałem długość ręcznie int b)
  2. Program zawiesza się po kilku sekundach.
#include <fstream>
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <string.h>
#include <bitset>

using namespace std;

int main()
{

    string str,napis;
    ifstream in;
    in.open("data.txt");
    getline(in,str);
    while ( in ) 
    {
      napis += str;
      getline(in,str);
    }

    int a, b, licznik = 0;

    //b = napis.length(); // nie działa poprawnie
    b = 78069;

    cout << "Dlugosc pliku: " << b << endl;

    ofstream myfile;
    myfile.open ("wynik.txt");

    for(a=0;a<b;a++)
    {
        if(napis[a] == napis[a+1]) licznik++;
        else
        {
            if(licznik>0) 
            {
               licznik = licznik-1;
               myfile << napis[a];
               myfile << napis[a];
               myfile << licznik;
               licznik = 0;
            }
            else 
            {
               myfile << napis[a]; 
            }       
        }
        cout << a << " / " << b << endl;            

    }

    myfile.close(); 

    cout << "Konwersja zakonczona" << endl;
    system("pause");
}

lukas_jg
Wyświetla Ci się długość pliku przed zawieszeniem? Użycie napis.length() działa dobrze, na pewno masz plik data.txt? - Zjarek 2011-10-04 11:29
Myślę, że napis.length() liczy długość tylko do znaku końca linii. Program działa do pewnego momentu. Zawiesza się przy kompresji plików >300kb. Plik data.txt istnieje. - lukas_jg 2011-10-04 11:58
Mylisz się, napis.length() działa bardzo dobrze. - Zjarek 2011-10-04 12:02
Proszę więc skompiluj ten kod powyżej. I odznacz komentarz "b = napis.length(); nie działa poprawnie" a następnie wrzuć do folderu powiedzmy plik regedit.exe (193Kb) i zamień jego nazwę na data.txt. b zwraca tylko 822 a plik jest dużo dłuższy. - lukas_jg 2011-10-04 12:07

Pozostało 580 znaków

2011-10-04 12:16
0

Problemem w tym wypadku może być występowanie w pliku znaków '\0' (takie przypuszczenie nie sprawdzane, ponieważ wszystko działa dobrze dla normalnych plików tekstowych), zmień sposób pobierania danych wejściowych. Dodatkowo pliki binarne musisz otwierać przez specjalny tryb, ponieważ w innym wypadku będzie sczytywać "\r\n" jako "\n" (getline w ogóle to odrzuci).

Sprawdź, czy po wczytaniu pliku jest ustawiany badbit, failbit, czy eofbit.

Mógłbyś mi podpowiedzieć jaką metodą pobierać dane? - lukas_jg 2011-10-04 12:34

Pozostało 580 znaków

2011-10-04 13:41
0

Tu masz przykład: http://www.cplusplus.com/reference/iostream/istream/tellg/


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2011-10-04 14:01
0

Super :) Udało się:

#include <iostream>
#include <fstream>
using namespace std;

int main () {
  int length;
  char * buffer;

  ifstream is;
  is.open ("test.txt", ios::binary );

  is.seekg (0, ios::end);
  length = is.tellg();
  is.seekg (0, ios::beg);

  buffer = new char [length];

  is.read (buffer,length);

  is.close();

    int a, b, licznik = 0;
    float postep;

    b = length;

    ofstream myfile;
    myfile.open ("archiwum.luk");

    for(a=0;a<b;a++)
    {
        if(buffer[a] == buffer[a+1]) licznik++;
        else
        {
            if(licznik>0) 
            {
               licznik = licznik-1;
               myfile << buffer[a];
               myfile << buffer[a];
               myfile << licznik;
               licznik = 0;
            }
            else 
            {
               myfile << buffer[a]; 
            }       
        }
    }

    myfile.close(); 

    cout << "Konwersja zakonczona" << endl;

}

Jeszcze pytanie. Co zrobić aby móc wpisać nazwę pliku jaki chcę wczytać?


lukas_jg

Pozostało 580 znaków

2011-10-04 14:43
0

Są dwa rozwiązania, możesz wczytać ze standardowego wejścia, lub przekazać jako argument. Podpowiedź: inna wersja main, szukaj argc i argv.

Pozostało 580 znaków

2011-10-04 15:17
0

A dlaczego masz dwa razy:

myfile << buffer[a];
myfile << buffer[a];

?

Żeby zapisało dwa takie same znaki, które oznaczają, że dany ciąg się powtarza i należy oczekiwać ilości powtórzeń po nich. (przykładowo: ABCDDDDDEFFG => ABCDD3EFF0G) - lukas_jg 2011-10-04 15:20
Hmm, a jak znak powtórzy Ci się 500 razy pod rząd? - darkbit 2011-10-04 15:38
to będzie AB...BC gdzie B wystąpił 500 => ABB499C - lukas_jg 2011-10-04 15:47
A jak tekst do kompresji będzie typu: "ABBB234" to wyjdzie "ABB2234"? I w wyniku dekompresji wyprodukujesz AB...(2235 x B)? - darkbit 2011-10-04 16:06
Kurcze... Trzeba się jakoś przed tym zabezpieczyć. Dzięki za przykład! - lukas_jg 2011-10-04 16:58
Poniżej dodałem poprawiony kod. Teraz przy dużej ilości znaków zostają one rozbite na grupy. - lukas_jg 2011-10-05 10:05

Pozostało 580 znaków

2011-10-05 10:05
0

Tutaj poprawiony kod:

#include <iostream>
#include <fstream>
using namespace std;

int main () {
  int length;
  char * buffer;

  ifstream is;
  is.open ("test.txt", ios::binary );

  is.seekg (0, ios::end);
  length = is.tellg();
  is.seekg (0, ios::beg);

  buffer = new char [length];

  is.read (buffer,length);

  is.close();

    int a, b, licznik = 0;
    float postep;

    b = length;

    ofstream myfile;
    myfile.open ("archiwum.luk");

    for(a=0;a<b;a++)
    {
        if(buffer[a] == buffer[a+1]) licznik++;
        else
        {
            while(licznik>10)
            {
               licznik = licznik-11;   
               myfile << buffer[a];
               myfile << buffer[a];
               myfile << 9;                      

            }                

            if((licznik>0) && (licznik<10)) 
            {
               licznik = licznik-1;
               myfile << buffer[a];
               myfile << buffer[a];
               myfile << licznik;
               licznik = 0;
            }
            else 
            {
               myfile << buffer[a]; 
            }       
        }
    }

    myfile.close(); 

    cout << "Konwersja zakonczona" << endl;

}

lukas_jg

Pozostało 580 znaków

2011-10-05 11:12
0

A jak wygląda kod dekompresujący? Działa dla np: skompresuj tekst "11234455656555577777" i zdekompresuj. Wyjdzie ok?
Dlaczego zapisujesz ilość powtórzeń dziesiętnie??? Ograniczasz się do 9 znaków. Użyj całej wartości bajta i już możesz mieć 256 znaków (0 to 1, 1 to 2 itp).

Pozostało 580 znaków

2011-10-05 11:55
0

W sumie można zrobić tak jak podpowiadasz :) 11234455656555577777 -> 11023440550656552773


lukas_jg

Pozostało 580 znaków

2011-10-05 12:29
0

11234455656555577777 -> 11023440550656552773

To chyba źle jest?
Dekompresując: wypisuje 1, wypisuje 1 razy 0, wypisuje 2, 3, 4, 4 razy 0... ? Huh? :]

Pozostało 580 znaków

2011-10-05 13:29
0

Nie, nie. To, że znak występuje 2 razy obok siebie informuje o tym, że te znaki będą powtarzane (xxn) 2x + n*x razy. ABCCCCDEEEFGGH -> AB CC2 D EE1 F GG0 H (C występuje 4 razy dlatego mamy CC + 2xC, G występuje tylko 2 razy więc mamy GG + 0xG)


lukas_jg
Ok. Rozumiem :] - darkbit 2011-10-05 14:14

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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