Operacje na plikach binarnych.

0

Witam mam problem z plikami binarnymi, piszę sobie w ramach ćwiczeń prosty paker plików czyli kompilacja kilku plików w jeden.
Poczytałem sobie na ten temat. Założyłem, że pierwsze 4 bajty mojego archiwum będą ilością plików w archiwum, kolejne X4 w zależności od ilości plików to wielkości plików, następnie X50 to nazwy. Wszystko działa bardzo fajnie i generalnie jest super, ale program działa tylko dla plików nie większych niż 1kb. Większe niby rozpakowuje(nawet mają odpowiednią wielkość) ale programy które powinny je otwierać informuję o błędach w plikach nie mam pojęcia gdzie może leżeć błąd. Więc zwracam się do was o pomoc.
O to kod:

main.cpp

#include <cstdlib>
#include <iostream>
#include "packer.h"

int main (){
    int in;
    //std::string in;
    std::cin>>in;

    Packer* packer;
    try{
        packer = new Packer("arch.amp");
        //std::cout<<packer->getFileSize("red.png")<<std::endl;
        //packer->praseInputLine("red.png;green.png;blue.png");
        packer->praseInputLine("red.png;green.png;blue.png;mus_maintheme.mp3");
        packer->createArchive();
        //std::cout<<packer->archiveFileSize(1)<<std::endl;
        //packer->unpackArchive();
        std::ofstream out("lol.mp3", std::ios::binary);
        int count = packer->archiveFilesCount();
        int size = packer->archiveFileSize(in);
        out.write(packer->archiveFileData(in, count), size);
        out.close();
    }
    catch(std::string e){
        std::cout<<e<<std::endl;
    }

    delete packer;

    system("pause");
    return 0;
}

packer.cpp:

#include <cstring>
#include <iostream>
#include "packer.h"

Packer::Packer(std::string archivefilename){
    archive = archivefilename;
}

void Packer::createArchive(){
    outfile.open(archive.c_str(), std::ios::binary);

    int i = (int)names.size();
    outfile.write((char*)&i, sizeof(i));
    for(std::vector<std::string>::iterator it = names.begin(); it != names.end(); it++){
        int len = getFileSize(*it);
        sizes.push_back(len);
        outfile.write((char*)&len, sizeof(len));
    }

    for(std::vector<std::string>::iterator it = names.begin(); it != names.end(); it++)
        outfile.write(std::string(*it).c_str(), 50);

    int size = names.size();
    for(int i=0; i<size; i++){
        infile.open(names[i].c_str(), std::ios::binary);

        if(!infile)
            throw std::string(names[i] + " not found!");

        buf = new char[sizes[i]];
        infile.read(buf, sizes[i]);
        outfile.write(buf, sizes[i]);
        infile.close();
        delete[] buf;
    }

    names.clear();
    sizes.clear();
    outfile.close();
}

void Packer::unpackArchive(){
    getArchiveInfo();
    int count = archiveFilesCount();

    infile.open(archive.c_str(), std::ios::binary);
    for(int i=0; i<count; i++){
        std::cout<<"Unpaking file no. "<<i+1<<" name: "<<names[i]<<" size: "<<sizes[i]<<std::endl;
        outfile.open(names[i].c_str(), std::ios::binary);
        if(i == 0)
            infile.seekg((count*sizeof(int))+(count*50));
        else
            infile.seekg((count*sizeof(int))+(count*50)+sizes[i-1]);
        buf = new char[sizes[i]];
        infile.read(buf, sizes[i]);
        outfile.write(buf, sizes[i]);
        infile.seekg(0, std::ios::beg);
        delete[] buf;
        outfile.close();
    }

    infile.close();
}

long Packer::getFileSize(std::string name){
    infile.open(name.c_str(), std::ios::binary);

    if(!infile)
        throw std::string(name + " not found!");

    long size;
    infile.seekg(0, std::ios::end);
    size = infile.tellg();
    infile.seekg(0, std::ios::beg);
    infile.close();

    return size;
}

int Packer::archiveFilesCount(){
    infile.open(archive.c_str(), std::ios::binary);

    if(!infile)
        throw std::string(archive + " not found!");

    int i;
    infile.read((char*)&i, sizeof(i));
    infile.close();

    return i;
}

char* Packer::archiveFileData(int index, int count){
    int size = 0, buflen = 0;
    for(int i=1; i<index; i++)
        size += archiveFileSize(i);

    buflen = archiveFileSize(index);

    infile.open(archive.c_str(), std::ios::binary);

    if(!infile)
        throw std::string(archive + " not found!");

    buf = new char[buflen];
    std::cout<<buflen<<" "<<size<<std::endl;
    std::cout<<(count*sizeof(int))+(count*50)+sizeof(int)+size<<std::endl;
    infile.seekg((count*sizeof(int))+(count*50)+sizeof(int)+size);
    infile.read(buf, buflen);
    infile.seekg(0, std::ios::beg);
    infile.close();
    delete[] buf;

    return buf;
}

std::string Packer::archiveFileName(int index, int count){
    infile.open(archive.c_str(), std::ios::binary);

    if(!infile)
        throw std::string(archive + " not found!");

    std::string sbuf;
    buf = new char[50];
    infile.seekg((count*sizeof(int))+((index-1)*50)+sizeof(int));
    infile.read(buf, 50);
    infile.seekg(0, std::ios::beg);
    infile.close();
    sbuf = std::string(buf);
    delete[] buf;

    return sbuf;
}

int Packer::archiveFileSize(int index){
    infile.open(archive.c_str(), std::ios::binary);

    if(!infile)
        throw std::string(archive + " not found!");

    int len;
    infile.seekg(index*sizeof(int));
    infile.read((char*)&len, sizeof(int));
    infile.seekg(0, std::ios::beg);
    infile.close();

    return len;
}

void Packer::praseInputLine(std::string line){
    char str[1024];
    sprintf(str, "%s", line.c_str());
    char* pch = strtok(str,";");

    while(pch != NULL){
        names.push_back(std::string(pch));
        pch = strtok(NULL, ";");
    }
}

void Packer::getArchiveInfo(){
    int count = archiveFilesCount();

    for(int i=1; i<=count; i++){
        names.push_back(archiveFileName(i, count));
        sizes.push_back(archiveFileSize(i));
    }
}

packer.h:

#ifndef PACKER_H
#define PACKER_H
#include <string>
#include <vector>
#include <fstream>

class Packer{
    public:
        Packer(std::string name);
        ~Packer(){};

        void praseInputLine(std::string);
        long getFileSize(std::string);
        void createArchive();
        void unpackArchive();
        int archiveFilesCount();
        std::string archiveFileName(int, int);
        int archiveFileSize(int);
        void getArchiveInfo();
        char* archiveFileData(int, int);

    private:
        char* buf;
        std::string archive;
        std::ifstream infile;
        std::ofstream outfile;
        std::vector<std::string>names;
        std::vector<int>sizes;
};

#endif //PACKER_H

Z góry dziękuję i pozdrawiam,
Miziak.

0

Założę się że pierwszy i drugi plik rozpakowywane dobrze. Problem jest tu:
infile.seekg((countsizeof(int))+(count50)+sizes[i-1]);
powinno być:
infile.seekg((countsizeof(int))+(count50)+sizes[i-1]+sizes[i-2]+sizes[i-3]+...+sizes[0]);
w pętle ma się rozumieć.

0
_13th_Dragon napisał(a):

Założę się że pierwszy i drugi plik rozpakowywane dobrze. Problem jest tu:
infile.seekg((countsizeof(int))+(count50)+sizes[i-1]);
powinno być:
infile.seekg((countsizeof(int))+(count50)+sizes[i-1]+sizes[i-2]+sizes[i-3]+...+sizes[0]);
w pętle ma się rozumieć.

Faktycznie ale to już poprawiłem w nowej wersji klasy mimo to problem z większymi plikami wystę puje totalnie nie wiem o co chodzi. Może rozwiązaniem będzie wczytywanie iż apis ich po kawałku??

Rozwiązałem problem poprawka wygląda tak może komuś się przyda:

void Packer::unpackArchive(){
    int count = archiveFilesCount();
    for(int i=1; i<=count; i++)
        archiveFileUnpack(i, count);
}

void Packer::archiveFileUnpack(int index, int count){
    int size = 0, buflen = 0;
    for(int i=1; i<index; i++)
        size += archiveFileSize(i);

    buflen = archiveFileSize(index);

    outfile.open(archiveFileName(index, count).c_str(), std::ios::binary);
    infile.open(archive.c_str(), std::ios::binary);

    if(!infile)
        throw std::string(archive + " not found!");

    bool under_kb = false;
    if(buflen < 1000)
        under_kb = true;

    for(buflen; buflen>0; buflen-=1000){
        if(buflen >= 1000){
            buf = new char[1000];
            infile.seekg((count*sizeof(int))+(count*50)+size);
            infile.read(buf, 1000);
            outfile.write(buf, 1000);
            infile.seekg(0, std::ios::beg);
            size += 1000;
            delete[] buf;
        }else{
            //std::cout<<"Unpaking file no. "<<index<<" name: "<<names[i]<<" size: "<<sizes[i]<<" position: "<<size<<" end size: "<<buflen<<std::endl;
            buf = new char[buflen];
            if(under_kb)
                infile.seekg((count*sizeof(int))+(count*50)+sizeof(int)+size);

            infile.read(buf, buflen);
            outfile.write(buf, buflen);
            infile.seekg(0, std::ios::beg);
            delete[] buf;
        }
    }

    outfile.close();
    infile.close();
}
0

Kurde jednak dalej jest coś nie tak, pliki wykonywalne(exe) po wypakowaniu nie działają, zauważyłem też dziwna prawidłowość pliki graficzne rozmiar > 1kb && rozmiar < 1mb również padają ma ktoś jakieś pomysły, mój z podziałem pliku na wczytywanie przez bufor po kawałku był dobry ale jak widać nie do końca może zapisywać też sekwencyjnie??

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