FILE pointers vs file streams

Started by
2 comments, last by ToohrVyk 16 years, 10 months ago
Hey, I'm attempting to write the D3DPRESENT_PARAMETERS structure to a file. I am currently using FILE* pointers, and the fread/fwrite functions, but it doesn't seem to want to open my .cfg files. Also I have used file streams in the past and I have no complaints about them. Is there any reason not to use them now? I almost like file pointers better, just cause the bit operators (<< >>) look ugly. Anyway, I'll throw my class down here so you guys can take a look-see. It's nothing fancy at all, I just want to get it working.

bool CORE::cGraphics::_LoadConfig(LPCSTR dir)
{
	if(dir == NULL)
		return false;
	FILE *cfg;
	
		if((fopen_s(&cfg, dir, "rb")) != NULL)
		{
			fread(&m_para->AutoDepthStencilFormat, 1,sizeof(m_para->AutoDepthStencilFormat), cfg);
		fread(&m_para->BackBufferCount, 1, sizeof(m_para->BackBufferCount), cfg);
		fread(&m_para->BackBufferFormat, 1, sizeof(m_para->BackBufferFormat), cfg);
		fread(&m_para->BackBufferHeight, 1, sizeof(m_para->BackBufferHeight), cfg);
		fread(&m_para->BackBufferWidth, 1, sizeof(m_para->BackBufferWidth), cfg);
		fread(&m_para->EnableAutoDepthStencil, 1, sizeof(m_para->EnableAutoDepthStencil), cfg);
		fread(&m_para->FullScreen_RefreshRateInHz, 1, sizeof(m_para->FullScreen_RefreshRateInHz), cfg);
		fread(&m_para->MultiSampleQuality, 1, sizeof(m_para->MultiSampleQuality), cfg);
		fread(&m_para->MultiSampleType, 1, sizeof( m_para->MultiSampleType), cfg);
		fread(&m_para->PresentationInterval, 1, sizeof(m_para->PresentationInterval), cfg);
		fread(&m_para->SwapEffect, 1, sizeof(m_para->SwapEffect), cfg);
		fread(&m_para->Windowed, 1, sizeof(m_para->Windowed), cfg);
		fclose(cfg);
		return true;
		}
		return false;
		
}

bool CORE::cGraphics::_SaveConfig(LPCSTR dir)
{
	FILE *cfg;
	if((fopen_s(&cfg, dir, "wb")) != NULL)
	{	
		fwrite(&m_para->AutoDepthStencilFormat, 1,sizeof(m_para->AutoDepthStencilFormat), cfg);
		fwrite(&m_para->BackBufferCount, 1, sizeof(m_para->BackBufferCount), cfg);
		fwrite(&m_para->BackBufferFormat, 1, sizeof(m_para->BackBufferFormat), cfg);
		fwrite(&m_para->BackBufferHeight, 1, sizeof(m_para->BackBufferHeight), cfg);
		fwrite(&m_para->BackBufferWidth, 1, sizeof(m_para->BackBufferWidth), cfg);
		fwrite(&m_para->EnableAutoDepthStencil, 1, sizeof(m_para->EnableAutoDepthStencil), cfg);
		fwrite(&m_para->FullScreen_RefreshRateInHz, 1, sizeof(m_para->FullScreen_RefreshRateInHz), cfg);
		fwrite(&m_para->MultiSampleQuality, 1, sizeof(m_para->MultiSampleQuality), cfg);
		fwrite(&m_para->MultiSampleType, 1, sizeof( m_para->MultiSampleType), cfg);
		fwrite(&m_para->PresentationInterval, 1, sizeof(m_para->PresentationInterval), cfg);
		fwrite(&m_para->SwapEffect, 1, sizeof(m_para->SwapEffect), cfg);
		fwrite(&m_para->Windowed, 1, sizeof(m_para->Windowed), cfg);
		fclose(cfg);
		return true;
	}
	return false;
}

That's about it. If someone could give me an answer as to why my file won't open (I'm directly passing "cfg.cfg" as the string) that would be great. Thanks to all-yall (I sound very southern in this, ironic, I'm a north easterner)
___________________________________________________Optimists see the glass as Half FullPessimists See the glass as Half EmptyEngineers See the glass as Twice as big as it needs to be
Advertisement
If you're running a debug build from within Visual Studio, check your working directory. Or, alternately, provide a full path for your configuration file.
Quote:Original post by Plasmarobo
Also I have used file streams in the past and I have no complaints about them. Is there any reason not to use them now?


No, not really.

Quote:I almost like file pointers better, just cause the bit operators (<< >>) look ugly.


Well, that sounds like you *do* have a complaint then. :) Can't say I really agree, though.

Anyway, those aren't "bit operators" in the context of file I/O, and they wouldn't be appropriate here anyway, because they do formatted rather than raw I/O (i.e. the stuff put into/expected from the file is human-readable). Of course, you can do raw I/O with file streams, as well, and gain all the usual benefits - not needing to worry about about separate "size" and "count" parameters, as well as not having to close the file explicitly.

And, that said, there are a few more things you can do to make things a lot cleaner: wrap up the sizeof() work and referencing work using a template function (I'm sorry, I don't have any explanation of why the C++ library doesn't do this already), use std::string to represent text, and use an early bailout when the file stream is invalid (remember, you won't have to close the file stream here, either - it's closed by the destructor of the object, which is automatically called).

template <typename T>void read(istream& is, T& t) {  is.read(reinterpret_cast<char*>(&t), sizeof(T));}template <typename T>void write(ostream& os, const T& t) {  os.write(reinterpret_cast<const char*>(&t), sizeof(T));}// Now we'll only need to specify two things each time we read or write// something - the stream, and the thing to read/write - just as it should be.bool CORE::cGraphics::_LoadConfig(const string& dir) {	// No such thing as a NULL string!	istream cfg(dir.c_str(), ios::binary);	if (!cfg) { return false; }		read(cfg, m_para->AutoDepthStencilFormat);	read(cfg, m_para->BackBufferCount);	read(cfg, m_para->BackBufferFormat);	read(cfg, m_para->BackBufferHeight);	read(cfg, m_para->BackBufferWidth);	read(cfg, m_para->EnableAutoDepthStencil);	read(cfg, m_para->FullScreen_RefreshRateInHz);	read(cfg, m_para->MultiSampleQuality);	read(cfg, m_para->MultiSampleType);	read(cfg, m_para->PresentationInterval);	read(cfg, m_para->SwapEffect);	read(cfg, m_para->Windowed);	return true;}bool CORE::cGraphics::_SaveConfig(const string& dir) {	// No such thing as a NULL string!	ostream cfg(dir.c_str(), ios::binary);	if (!cfg) { return false; }		write(cfg, m_para->AutoDepthStencilFormat);	write(cfg, m_para->BackBufferCount);	write(cfg, m_para->BackBufferFormat);	write(cfg, m_para->BackBufferHeight);	write(cfg, m_para->BackBufferWidth);	write(cfg, m_para->EnableAutoDepthStencil);	write(cfg, m_para->FullScreen_RefreshRateInHz);	write(cfg, m_para->MultiSampleQuality);	write(cfg, m_para->MultiSampleType);	write(cfg, m_para->PresentationInterval);	write(cfg, m_para->SwapEffect);	write(cfg, m_para->Windowed);	return true;		}


But even then... all this 'm_para->' business is rather irritating. It suggests that these functions should really be members of that structure; we can simply call the structure's implementation from the Graphics object functions, to keep the old interface (delegation).

Quote:
That's about it. If someone could give me an answer as to why my file won't open (I'm directly passing "cfg.cfg" as the string) that would be great.


Where on disk is the executable that is actually being run? Are you 100% sure?
Where on disk is the 'cfg.cfg' that you want to open?
Quote:Original post by Zahlman
And, that said, there are a few more things you can do to make things a lot cleaner: wrap up the sizeof() work and referencing work using a template function (I'm sorry, I don't have any explanation of why the C++ library doesn't do this already)


It probably doesn't do this because it isn't useful. The memory representation of all basic types is implementation-defined (because endianness may vary from platform to platform, but also for 64-bit int and 18-bit char issues), so writing objects to disk as a reinterpret_cast<const char*>(&foo) is nonportable—and that's assuming that the object has a memory layout to begin with (so 99% of objects wouldn't be usable this way anyway).

Either way, boost has the quite nice boost::serialization library (which also, as Zahlman suggests, moves the serialize-unserialize responsibility to m_para). Simply add the following function to the class/structure of m_para:

  friend class boost::serialization::access;  template<class Archive>  void serialize(Archive & ar, const unsigned int version)  {    ar       & BackBufferCount       & BackBufferFormat      & BackBufferHeight      & BackBufferWidth      & EnabuleAutoDepthStencil      & RefreshRateInHz      & MultiSampleQuality      & MultiSampleType      & PresentationInterval      & SwapEffect      & Windowed;  }


This is enough to enable both loading and saving.

This topic is closed to new replies.

Advertisement