Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

[C++] Vaag file open probleem

Pagina: 1
Acties:
  • 200 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Ik ben een applicatie schrijven die aan de hand van XML communicatie verzorgt met bepaalde apparaten, dat werkt allemaal geweldig. Ook is er een mogelijkheid om een bestand als een apparaat te zien, dus de inhoud van die file is een output van een apparaat. Dit was de korte intro.

Ik heb een thread met de volgende sequence:

- laad html-template uit een bestand voor rapportage
- ga voor elk apparaat in de lijst de xml parsen.
- sla het bewerkte html-template (rapport dus) op.

Dit gaat perfect als de apparaten alleen maar echte apparaten zijn en dus geen file I/O hoeven te doen. Zodra ik dus een stuk XML heb dat bepaald dat ik uit een bestand data moet lezen kan ik opeens stap 3 niet meer doen, haal ik stap 3 naar voren, dus voor stap 2, dan werkt het opslaan opeens wel weer. Er zit dus duidelijk iets fout in stap 2. ik heb gechecked op handles die gesloten worden, maar ze worden allemaal netjes afgesloten.

Nu even de I/O-flow van mijn applicatie:

stap 1 (std::ios_base::in):

- std::fstream > open("html/report.temlate");
- std::fstream > read();
- std::fstream > close();

stap 2 (std::ios_base::in):

Voor elke apparaat dat de data in een bestand uitleest:

- std::fstream > open("volledig pad naar bestand");
- std::fstream > read();
- std::fstream > close();

stap 3 (std::ios_base::out | std::ios_base::trunc)
- std::fstream > open("reports/temp.html");

en daar gaat het dan fout er wordt geen bestand aangemaakt. Nu komt het vreemde, als ik dus geen bestanden inlees in stap 2 dus alleen directe I/O op de andere apparaten werkt stap 3 wel opeens. Alle handles worden echt gesloten. Om een en ander uit te sluiten zal ik hier de code neergooien van de klasse die ik gebruik om met de files te interfacen:

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
typedef struct __FileConfig
{
    char* fileName;
    bool isWriteable;
    bool isReadable;

} FileConfig;

class Connector
{
// public access data
public:
    // Constructors/Deconstructors:
    Connector();
    virtual ~Connector();

    //Member functions:

    // Init & Termination
    virtual bool connect(void* config) = 0;
    virtual bool disconnect() = 0;

    // RW-OPS
    virtual bool read(char* buffer, size_t length) = 0;
    virtual bool write(char* buffer, size_t length) = 0;

    bool rxFlag;
    bool rxEndFlag;

    virtual void clearBuffer() = 0;
    virtual void waitForCompletion() = 0;

// private data
private:

// protected data
protected:

    bool connected;
};

class FileConnector : public Connector
{
// public access data
public:
    // Constructors/Deconstructors:
    FileConnector();
    ~FileConnector();

    //Member functions:

    // Init & Termination
    bool connect(void* config);
    bool disconnect();

    void clearBuffer();
    void waitForCompletion();

    // RW-OPS
    bool read(char* buffer, size_t length);
    bool write(char* buffer, size_t length);

// private data
private:

    std::fstream* fileHandle;

    FileConfig* configuration;

// protected data
protected:
};

bool FileConnector::connect(void* config)
{
    DEBUG("FileConnector::connect()");

    // check if we are already connected
    if(!this->connected)
    {
        // set config pointer
        this->configuration = (FileConfig*)config;

        /* debug */
        DEBUG("BEGIN DEVICE CONFIG");
        DEBUG("fileName: " << this->configuration->fileName);
        DEBUG("isWriteable: " << this->configuration->isWriteable);
        DEBUG("isReadable: " << this->configuration->isReadable);
        DEBUG("END DEVICE CONFIG");

        /* create handle with right read/write flags */
        if(this->configuration->isWriteable && !this->configuration->isReadable)
            this->fileHandle = new std::fstream(this->configuration->fileName, std::ios_base::out | std::ios_base::trunc);
        else if (this->configuration->isReadable && !this->configuration->isWriteable)
            this->fileHandle = new std::fstream(this->configuration->fileName, std::ios_base::in);
        else
            this->fileHandle = new std::fstream(this->configuration->fileName, std::ios_base::out | std::ios_base::in | std::ios_base::trunc);

        /* check if file was opened correctly */
        if(!this->fileHandle->is_open())
        {
            return false;
        }

        /* we are connected */
        this->connected = true;
    }
    else
        return false;

    return true;
}

/* Function: disconnect
 * Description: Disconnects the device
 *
 * Param(s): none
 *
 * Returns: state of function call
 */
bool FileConnector::disconnect()
{
    DEBUG("FileConnector::disconnect()");

    /* check */
    if(this->connected)
    {
        /* close stream */
        this->fileHandle->close();

        /* free the pointer */
        delete this->fileHandle;

        this->connected = false;
    }
    else
        return false;

    return true;
}

/* Function: read
 * Description: read a number of bytes from a device
 *
 * Param(s): 
 *
 * - buffer: a pointer to a buffer to write the data to
 * - length: the number of bytes to read
 *
 * Returns: state of function call
 */
bool FileConnector::read(char* buffer, size_t length)
{
    DEBUG("FileConnector::read(null, " << length << ")");

    if(this->connected && this->configuration->isReadable)
    {
        this->fileHandle->read(buffer, static_cast<std::streamsize>(length));

        this->rxFlag = false;
        this->rxEndFlag = false;
    }
    else
        return false;

    return true;
}

/* Function: write
 * Description: write a number of bytes to a device
 *
 * Param(s): 
 *
 * - buffer: a pointer to a buffer to write the data to
 * - length: the number of bytes to read
 *
 * Returns: state of function call
 */
bool FileConnector::write(char* buffer, size_t length)
{
    DEBUG("FileConnector::write(" << buffer << ", " << length << ")");

    if(this->connected && this->configuration->isWriteable)
    {
        this->fileHandle->write(buffer, static_cast<std::streamsize>(length));
    }
    else
        return false;

    return true;
}


Ik word er een beetje gek van :(

edit: Ohja, als ik de C-library gebruik (fopen() etc) bij stap 3 dan krijg ik hetzelfde bij std::fstream

  • sam.vimes
  • Registratie: Januari 2007
  • Laatst online: 08-06 08:44
Ik heb het vermoeden dat je buiten het object steeds je configuration wijzigt omdat het een pointer is naar iets dat buiten het object ligt.
Verander regel 68 eens in
C++:
1
FileConfig configuration;

en 82 in
C++:
1
this->configuration = *(FileConfig*)config;

(en alle "configuration->" in "configuration.").

Zodoende wordt het object "eigenaar" van de configuration in plaats van dat het verwijst naar een of andere config buiten het object waarvan je maar moet hopen dat het de gewenste waarden heeft op het moment dat je de members isWriteable en isReadable opvraagt.

Misschien moet je zelfs de
C++:
1
char* fileName;

in regel 3 wijzigen in
C++:
1
std::string fileName;



N.B. "this->" is vrijwel altijd redundant en kan worden weggelaten.
Verder is in C++ de constructie "struct naam" automatisch ook een typedef voor naam, zodat
C++:
1
2
3
4
typedef struct __FileConfig
{
    ...
} FileConfig;

kan worden ingekort tot
C++:
1
2
3
4
struct FileConfig
{
    ...
};

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:17

.oisyn

Moderator Devschuur®

Demotivational Speaker

sam.vimes schreef op dinsdag 15 januari 2008 @ 09:41:
N.B. "this->" is vrijwel altijd redundant en kan worden weggelaten.
Desalniettemin kan het for sake of readability best nuttig zijn om het erin te houden. (En het is ook practisch als je in een template class zit en je wil een name van een dependent base class gebruiken, maar da's hier natuurlijk niet van toepassing en die situatie zal de TS waarschijnlijk niet snel tegenkomen ;))

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
sam.vimes schreef op dinsdag 15 januari 2008 @ 09:41:
Ik heb het vermoeden dat je buiten het object steeds je configuration wijzigt omdat het een pointer is naar iets dat buiten het object ligt.
Verander regel 68 eens in
C++:
1
FileConfig configuration;

en 82 in
C++:
1
this->configuration = *(FileConfig*)config;

(en alle "configuration->" in "configuration.").

Zodoende wordt het object "eigenaar" van de configuration in plaats van dat het verwijst naar een of andere config buiten het object waarvan je maar moet hopen dat het de gewenste waarden heeft op het moment dat je de members isWriteable en isReadable opvraagt.

Misschien moet je zelfs de
C++:
1
char* fileName;

in regel 3 wijzigen in
C++:
1
std::string fileName;



N.B. "this->" is vrijwel altijd redundant en kan worden weggelaten.
Verder is in C++ de constructie "struct naam" automatisch ook een typedef voor naam, zodat
C++:
1
2
3
4
typedef struct __FileConfig
{
    ...
} FileConfig;

kan worden ingekort tot
C++:
1
2
3
4
struct FileConfig
{
    ...
};
Configuration wordt alleen gebruikt om de filename te verkrijgen en de juiste openmode te vinden. Dat werkt allemaal perfect. Het gaat erom dat ik zelfs als ik een andere methode gebruik dus fopen() ter voorbeeld dat ik geen files meer kan openenen voor writing, als read-only openen is geen probleem. Alle handles worden afgesloten, maar toch snap ik niet waarom hij niet een writeable file kan openen als ik 2 specifieke files heb geladen (filename heb ik verkregen door GetOpenFileName() ) als ik dit niet doe werkt alles perfect!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

dit lijkt me nogal raar:
code:
1
std::ios_base::out | std::ios_base::in | std::ios_base::trunc


kan deze combinatie?

ASSUME makes an ASS out of U and ME


Verwijderd

Topicstarter
H!GHGuY schreef op dinsdag 15 januari 2008 @ 19:33:
dit lijkt me nogal raar:
code:
1
std::ios_base::out | std::ios_base::in | std::ios_base::trunc


kan deze combinatie?
Die wordt in dit geval nogeneens gebruikt dus dat is niet van belang ;)

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
Lijkt me een gevalletje debuggen eerlijk gezegd, test waar het fout gaat en waarom. Een uitspraak als 'kan ik stap 3 niet meer doen' vind ik te vaag om iets zinnigs over te kunnen zeggen.

Als je bestanden wilt uitlezen die nog niet zolang geleden geschreven zijn kun je een probleem tegenkomen ivm caching van het filesysteem.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:17

.oisyn

Moderator Devschuur®

Demotivational Speaker

Als je de file fysiek gesloten hebt zou het wel heel dom zijn dat je die informatie niet krijgt als je 'm direct erna weer opent. Of het nou al naar disk is geschreven of niet, je hoort de juiste info te krijgen. Zonder dergelijke coherency kun je je PC wel in de prullenbak deponeren.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
farlane schreef op dinsdag 15 januari 2008 @ 20:20:
Lijkt me een gevalletje debuggen eerlijk gezegd, test waar het fout gaat en waarom. Een uitspraak als 'kan ik stap 3 niet meer doen' vind ik te vaag om iets zinnigs over te kunnen zeggen.
Als je bestanden wilt uitlezen die nog niet zolang geleden geschreven zijn kun je een probleem tegenkomen ivm caching van het filesysteem.
Het is niet dezelfde file ;) Het is juist een andere file (ik lees een paar, daarna open ik er 1 voor het schrijven ernaar), ik vermoed dat er een bug in de library van Vistual Studio 2005 zit, ook heb ik te maken met een hele brakke compiler, als ik enige vorm van optimalisatie inschakel bij het compilen krijg ik binary's die at random crashen.

edit: over dat debuggen, ik heb een debug-log waarin ik alle calls naar functies die gedaan worden kan zien en alle functies worden echt correct aangeroepen. :/

UPDATE: Als ik GetOpenFileName() niet gebruik maar gewoon een hardcoded filename gebruik heb ik het probleem niet, het is dus de win32 API

Nu alleen nog een manier om het op te lossen

Relevante stukje code:

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
if(currentValue == "%USER%")
{
    // get filename from user
    OPENFILENAME ofn;       // common dialog box structure
    wchar_t szFile[260];       // buffer for file name
    HANDLE hf;              // file handle

    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = dialogHandle;
    ofn.lpstrFile = szFile;

    //
    // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
    // use the contents of szFile to initialize itself.
    //
    ofn.lpstrFile[0] = '\0';
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFilter = L"All\0*.*\0Text\0*.TXT\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    int getOpenFileNameStatus = GetOpenFileName(&ofn);
    DEBUG("GetOpenFileName: " << getOpenFileNameStatus);

    char * fileName = (char*)malloc(260);

    CharToOem(szFile, fileName);
                        
    strncpy(config->fileName, fileName, 260);

    free(fileName);
}


als ik ipv CharToOem(szFile, fileName); CharToOem(L"test.txt", fileName) doe en GetOpenFileName() niet uitvoer dan werkt het opeens wel, dus GetOpenFileName is echt de boosdoener.

[ Voor 56% gewijzigd door Verwijderd op 15-01-2008 21:46 ]


Verwijderd

Topicstarter
Even een nieuwe post want het is gefixed!! :)

GetOpenFileName() veranderd de current working directory als je browsed, ik vind het zelf niet correct dat, dat gebeurd, maar ik heb het gefixed door de oude cwd op te slaan en dan de GetOpenFileName() te doen en daarna weer de cwd correct te zetten.

C++:
1
2
3
4
5
6
7
8
wchar_t directoryBuffer[512];

GetCurrentDirectory(512, directoryBuffer);

int getOpenFileNameStatus = GetOpenFileName(&ofn);
DEBUG("GetOpenFileName: " << getOpenFileNameStatus);

SetCurrentDirectory(directoryBuffer); 


of OFN_NOCHANGEDIR als flag meegeven

Bedankt voor alle hulp!! :)

edit: ohja voor de geïnteresseerden, dit was mijn bron: http://groups.google.com/...86c052%239abd201efa86c052

Misschien handig voor de search

[ Voor 19% gewijzigd door Verwijderd op 15-01-2008 22:28 ]


  • sam.vimes
  • Registratie: Januari 2007
  • Laatst online: 08-06 08:44
Verwijderd schreef op dinsdag 15 januari 2008 @ 21:31:
[...]
C++:
1
2
3
4
5
6
    ...
    char * fileName = (char*)malloc(260);
    ...
    strncpy(config->fileName, fileName, 260);
    free(fileName);
}

[...]
Waarom hier niet gewoon
C++:
1
2
3
4
5
    ...
    char fileName[260];
    ...
    strncpy(config->fileName, fileName, sizeof fileName);
}

Voordelen:
  • geen controle op de returnwaarde van malloc() nodig (die bij jou ontbreekt: oeps!)
  • geen free() meer nodig
  • de magische constante 260 komt op nog maar 1 plaats voor (nog beter is op 0 plaatsen, ik denk dat je PATH_MAX of zoiets nodig hebt)

Verwijderd

Topicstarter
Misschien omdat ik de grote van de binary wil beperken ;) Als je dat doet wordt die ruimte in de scope van de applicatie zelf gealloceerd en niet in het vrije geheugen, dus daarom heb ik dat dus niet gedaan, mijn code m.b.t. CWD heb ik nu ook al veranderd omdat ie 512 * 2 bytes = 1KB is, dus dan maar even uit het geheugen allocaten.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:17

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee hoor, die data staat op de stack. Bovendien, gebruik dan gewoon std::string.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
.oisyn schreef op woensdag 16 januari 2008 @ 11:15:
Nee hoor, die data staat op de stack. Bovendien, gebruik dan gewoon std::string.
Ik ben gewend kernels te schrijven en daar gooide ik ze nooit in de stack maar in de binary zelf. Zal wel een configuratie-iets zijn van mijn compiler

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
.oisyn schreef op dinsdag 15 januari 2008 @ 21:11:
Als je de file fysiek gesloten hebt zou het wel heel dom zijn dat je die informatie niet krijgt als je 'm direct erna weer opent. Of het nou al naar disk is geschreven of niet, je hoort de juiste info te krijgen. Zonder dergelijke coherency kun je je PC wel in de prullenbak deponeren.
Ik heb geen idee of het na het sluiten van het bestand ook nog kan voorkomen eerlijk gezegd, lijkt me niet ).

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:17

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op woensdag 16 januari 2008 @ 17:08:
[...]


Ik ben gewend kernels te schrijven en daar gooide ik ze nooit in de stack maar in de binary zelf. Zal wel een configuratie-iets zijn van mijn compiler
Als je ze als static definieert, of simpelweg in namespace scope, dan komen ze idd in de binary. Maar het lijkt me stug dat je compiler een optie heeft om lokale variabelen in een datasection te proppen, dat zou namelijk impliceren dat je functie niet meer reentrant is en er geen reet meer klopt van het verwachtte gedrag van lokale variabelen.

Daarnaast reageer je voor het gemak maar even niet op het belangrijkste deel van mijn post ;)

[ Voor 7% gewijzigd door .oisyn op 16-01-2008 18:39 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Verwijderd schreef op woensdag 16 januari 2008 @ 17:08:
[...]
Ik ben gewend kernels te schrijven en daar gooide ik ze nooit in de stack maar in de binary zelf. Zal wel een configuratie-iets zijn van mijn compiler
In het algemeen kan de compiler dat niet doen; functies moeten recursief aangeroepen kunnen worden. Alleen als de compiler kan bewijzen dat dat niet het geval is, kan de compiler de buffer naar het uninitialized data segment verhuizen. Maar in dat geval heb je nog steeds geen ruimte in de binary nodig (want uninitialized)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Topicstarter
De reden waarom ik dit dacht, kwam door het feit dat mijn binaray's groter werden als ik iets had als char blaat[4000]; in mijn code. :) Maargoed, het probleem is opgelost en heb geen zin in verdere discussies :Y)
Pagina: 1