Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   

Die mobilen Seiten von c++.de:
http://m.c-plusplus.de
Infos hier [BETA]

  
c++.de :: C++ (auch C++0x und C++11) ::  Datei einlesen in eine verkettete Liste     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
build
Mitglied

Benutzerprofil
Anmeldungsdatum: 21.06.2012
Beiträge: 16
Beitrag build Mitglied 12:17:20 21.06.2012   Titel:   Datei einlesen in eine verkettete Liste            Zitieren

Hallo,

ich habe ein kleines, eig. sogar 2 Probleme:
Ich versuche eine Datei einzulesen (binär) und diese in eine verkettete Liste zu speichern um sie später über ein Socket an einen Client oder Server zu senden.

Probleme:
i) Das ganze läuft sehr unperformant. Es dauert schon einiges an Zeit bei >1MB
ii)Teilweise wird nicht die ganze Datei reingeladen

Im folgenden Codeabschnitt ist eig. die ganze Logik des dargestellten Problemes:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#define MAX_PACKET_SIZE 1024        // Maximale Packetgroesse (in Byte)
 
// Packet::pos - Derzeitige Position in unserem Paket
// Packet::PacketCount - Anzahl der Pakete
 
struct PacketTransmission
{
    unsigned char   data[MAX_PACKET_SIZE];  // Daten an sich
    PacketTransmission *nextPacket;         // Naechstes Paket
 
    bool HasNext();
};
struct PacketBase
{
    unsigned short op_code;     // Verwendeter Anfragecode
    unsigned int filename_length;   // Laenge des Dateinnamen
    std::string filename;       // Dateiname
    PacketTransmission *pData;  // Pointer zu unseren eigentlichen Daten
};
 
// Liest eine Datei in ein Paket ein
bool Packet::FileToPacket()
{
    // Datei oeffnen und jedes Zeichen auslesen und in das Paket eintragen
    std::ifstream file(pb.filename, std::ios::in | std::ios::binary);
 
    char buffer[MAX_PACKET_SIZE];
    // Solange durchgehen bis wie
    while(!file.eof())
    {
        file.read(buffer, MAX_PACKET_SIZE);
        this->AddString(buffer);
    }
 
    file.close();
 
    return true;
}
 
// Ein Byte zum Paket hinzufuegen
bool Packet::AddByte(unsigned char byte)
{
    // Wenn das aktuelle Paket voll ist, erstellen wir das naechste und verknuepfen es
    if(pos >= MAX_PACKET_SIZE)
    {
        pos = 0;                    // Wieder am Anfang setzen
        PacketCount++;              // Wir haben ein Paket mehr
 
        PacketTransmission *ptrans = new PacketTransmission;
        ptrans = pb.pData;
        // Solange durchgehen bis wir ein neues Paket frei haben
        while(ptrans->HasNext())
            ptrans = ptrans->nextPacket;
 
        PacketTransmission *newPacket = new PacketTransmission;
        newPacket->data[pos++] = (unsigned char)byte;
        newPacket->nextPacket = NULL;
 
        ptrans->nextPacket = newPacket;
    }
    // Wir haben noch Platz
    else
    {
        PacketTransmission *ptrans = new PacketTransmission;
 
        if(pb.pData != NULL)
        {
            ptrans = pb.pData;
            while(ptrans->HasNext())
                ptrans = ptrans->nextPacket;
 
            ptrans->data[pos++] = (unsigned char)byte;
        }
        else
        {
            pb.pData = new PacketTransmission();
            pb.pData->data[pos++] = (unsigned char)byte;
        }
    }
    return true;
}
 
// Ein String hinzufuegen
void Packet::AddString(const char *str)
{
    // Gueltiger String
    if(str == NULL || strlen(str) == 0) return;
 
    // Alle Elemente eintragen (per AddByte)
    for(int i = 0; i < MAX_PACKET_SIZE; i++)
        AddByte(str[i]);
}


Vielen Dank im Voraus!


Zuletzt bearbeitet von build am 12:36:07 21.06.2012, insgesamt 1-mal bearbeitet
Werner Salomon
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.07.2005
Beiträge: 2154
Beitrag Werner Salomon Mitglied 12:58:49 21.06.2012   Titel:              Zitieren

Hallo build,

Willkommen im C++-Forum.

Dein Programm ist deshalb so langsam, weil Du beim Abspeichern jedes einzelnen Bytes die komplette Liste von vorne bis hinten durchläufst, um zum letzten Element PacketTransmission zu gelangen. Und weil Du mit jedem Byte ca. 1k Speicher allokierst ohne ihn freizugeben!

Tipp: lege Dir vor(!) dem Lesen (vor Zeile 31) bereits eine Instanz von PacketTransmission an und lese direkt in den Buffer(data) dieser Instanz. Hänge sie anschließend an das Ende Deiner Liste (dann darfst Du sie auch ganz durchlaufen). Das dürfte um etliche Größenordnungen schneller sein.

Ansonsten gibt es noch ganz viel zu Deinem Programmcode zu sagen, aber vielleicht später. Z.B.: schaue Dir mal gcount an und ersetze in den Zeilen 49 und 64
C++:
PacketTransmission *ptrans = new PacketTransmission;
durch
C++:
PacketTransmission *ptrans = 0;
Dein Programm wird dann bereits etwas schneller laufen als vorher.

Gruß
Werner


Zuletzt bearbeitet von Werner Salomon am 13:13:39 21.06.2012, insgesamt 1-mal bearbeitet
build
Mitglied

Benutzerprofil
Anmeldungsdatum: 21.06.2012
Beiträge: 16
Beitrag build Mitglied 13:31:54 21.06.2012   Titel:              Zitieren

Das klingt auf jeden Fall schon einmal sinnvoll. Danke dafür.
Zudem sorgt ein new bei jeder Iteration wohl für sehr große Speicherlecks.

Ich habe mich daher für die Lösung entschieden, welche leider Exceptions wirft.
Allerdings sehe ich den Fehler gerade selbst nicht.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void Packet::AppendData(unsigned char data[MAX_PACKET_SIZE])
{
    if(pb.pData == NULL)
        {
        AddString((const char*)data);
                return;
        }
 
    PacketTransmission *pt      = new PacketTransmission;
    PacketTransmission *next    = 0;
 
    next = pb.pData;
    memcpy(pt->data, data, MAX_PACKET_SIZE);
 
    while(next->HasNext())
        next = next->nextPacket; // Hier kommt nach ein paar Iterationen die Exception
 
    next->nextPacket = pt;
    PacketCount++;
 
}
 
bool Packet::PacketTransmission::HasNext()
{
    if(this == NULL)
        return false;
 
    else
    {
        if(nextPacket == NULL)
            return false;
    }
 
    return true;
}


EDIT:
Problem gelöst:
ein pt.nextPacket = NULL hat gefehlt


Zuletzt bearbeitet von build am 14:01:01 21.06.2012, insgesamt 2-mal bearbeitet
build
Mitglied

Benutzerprofil
Anmeldungsdatum: 21.06.2012
Beiträge: 16
Beitrag build Mitglied 14:28:55 21.06.2012   Titel:              Zitieren

Die Performanceprobleme wären gelöst.
Das Problem mit den fehlenden Bytes leider nicht. Es liegt nicht am recv / send der Sockets. Das Problem entsteht beim reinladen und verknüpfen.
Bei einer 150KB Datei fehlten 5KB. Bei einer kleinen 2KB Datei fehlten nur 7-8 Zeichen am Ende der Datei.

Der Tipp mit gcount würde es natürlich dynamischer, aber eig. müsste es ja auch mit 1KiB-Blöcken funktionieren. Eher passiert es doch, dass am Ende ein paar Byte zuviel statt zuwenig sind!?
c++.de :: C++ (auch C++0x und C++11) ::  Datei einlesen in eine verkettete Liste   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.