www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - r/w binary

reply Joel Christensen <joelcnz gmail.com> writes:
I want to save and load levels for my game. The std.stream module 
doesn't have much examples.

Here is my code:
void saveLevel( string fileName ) {
	auto bfile = new std.stream.File;

	int ver = 1;
	string verStr = "version:";
	with( bfile ) {
		scope( exit )
			close;
		create( fileName );
		write( verStr ); write( ver ); // version
	}

	int ver2;
	char[] verStr2;
	auto bfile2 = new std.stream.File;
	with( bfile2 ) {
		scope( exit )
			close;
		create( fileName );
		read( verStr2 ); read( ver2 ); // version
	}
	writeln( verStr, ver );
}

And this is the result:
std.stream.ReadException std\stream.d(46): Stream is not readable

- Joel
Jun 28 2011
parent reply Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
I've settled on std.stdio as opposed to std.stream and std.cstream.

On Wed, 29 Jun 2011 10:07:13 +1200, Joel Christensen wrote:

 I want to save and load levels for my game. The std.stream module
 doesn't have much examples.
 
 Here is my code:
 void saveLevel( string fileName ) {
 	auto bfile = new std.stream.File;
 
 	int ver = 1;
 	string verStr = "version:";
 	with( bfile ) {
 		scope( exit )
 			close;
 		create( fileName );
 		write( verStr ); write( ver ); // version
 	}
 
 	int ver2;
 	char[] verStr2;
 	auto bfile2 = new std.stream.File;
 	with( bfile2 ) {
 		scope( exit )
 			close;
 		create( fileName );

That is copy-paste mistake, right? You don't want create() before reading. You must have meant open: open( fileName ); It works with that change.
 		read( verStr2 ); read( ver2 ); // version
 	}
 	writeln( verStr, ver );
 }
 
 And this is the result:
 std.stream.ReadException std\stream.d(46): Stream is not readable
 
 - Joel

Ali
Jun 28 2011
next sibling parent reply Joel Christensen <joelcnz gmail.com> writes:
Thanks for your reply Ali.

Your right about changing create to open when reading. And, yes, I was 
thinking of trying std.stdio myself.

- Joel

On 29-Jun-11 6:48 PM, Ali Çehreli wrote:
 I've settled on std.stdio as opposed to std.stream and std.cstream.

 On Wed, 29 Jun 2011 10:07:13 +1200, Joel Christensen wrote:

 I want to save and load levels for my game. The std.stream module
 doesn't have much examples.

 Here is my code:
 void saveLevel( string fileName ) {
 	auto bfile = new std.stream.File;

 	int ver = 1;
 	string verStr = "version:";
 	with( bfile ) {
 		scope( exit )
 			close;
 		create( fileName );
 		write( verStr ); write( ver ); // version
 	}

 	int ver2;
 	char[] verStr2;
 	auto bfile2 = new std.stream.File;
 	with( bfile2 ) {
 		scope( exit )
 			close;
 		create( fileName );

That is copy-paste mistake, right? You don't want create() before reading. You must have meant open: open( fileName ); It works with that change.
 		read( verStr2 ); read( ver2 ); // version
 	}
 	writeln( verStr, ver );
 }

 And this is the result:
 std.stream.ReadException std\stream.d(46): Stream is not readable

 - Joel

Ali

Jun 29 2011
parent reply Joel Christensen <joelcnz gmail.com> writes:
With the char[], I can't use spaces in it the way I've got it here, 
(like if I tried using a phrase):

void saveLevel( string fileName ) {
	int ver = 1;
	auto house = "two".dup;
	double rnum = 3.0;
	
	{
		auto fout = File( fileName, "wb"); // open for binary writing
		scope( exit )
			fout.close;
		fout.writef( "%d %s %f", ver, house, rnum );
	}
	
	ver = 593;
	house = "asdfghf".dup;
	rnum = 57.23;

	{
		auto fin = File( fileName, "rb"); // open for binary reading
		scope( exit )
			fin.close;
		fin.readf( "%d %s %f", &ver, &house, &rnum );
	}

	writeln( "\nint: ", ver, " string: '", house, "' rnum: ", rnum );
}

- Joel
Jun 29 2011
parent reply Joel Christensen <joelcnz gmail.com> writes:
I'm thinking more about handling binary files. With the C version I 
would write a int for how many letters in the string, then put in the 
the string along side ([0005][house]). That way I can have any character 
at all (though I just thinking of char's).

Actually, I've just looked the output file and it's a text file. So in 
that case I would use read line to have spaces in strings, though what 
if I wanted to have new line character(s) in the one string. I still 
want to work with binary files.

On 30-Jun-11 2:23 AM, Ali Çehreli wrote:
 On Wed, 29 Jun 2011 19:55:38 +1200, Joel Christensen wrote:

 With the char[], I can't use spaces in it the way I've got it here,
 (like if I tried using a phrase):

There has been a thread very recently about reading strings. Look for the thread "readf with strings" (dated 22-Jun-2011 in my reader). Or, if it works here: http://www.digitalmars.com/webnews/newsgroups.php? art_group=digitalmars.D.learn&article_id=27762 Reading the entire line: string s = chomp(readln()); Kai Meyer suggested parsing the string directly: string[] buffer; int a; float b; string c; buffer = chomp(readln()).split(" "); a = to!(int)(buffer[0]); b = to!(float)(buffer[1]); c = buffer[2..$].join(" "); writef("Read in: '%d' '%f' '%s'\n", a, b, c);
 void saveLevel( string fileName ) {
 	int ver = 1;
 	auto house = "two".dup;
 	double rnum = 3.0;
 	
 	{
 		auto fout = File( fileName, "wb"); // open for binary

 		exit )
 			fout.close;

You are not supposed to need to close the File object yourself. Being a struct, its destructor should be called automatically. Ali

Jun 29 2011
parent reply Joel Christensen <joelcnz gmail.com> writes:
Yes, portability, I hadn't thought of that.

Shouldn't file.rawWrite((&i)[0..1]); have [0..4]? Or am I missing some 
thing?

- Joel

On 30-Jun-11 7:53 PM, Ali Çehreli wrote:
 On Thu, 30 Jun 2011 15:52:59 +1200, Joel Christensen wrote:

 I'm thinking more about handling binary files. With the C version I
 would write a int for how many letters in the string, then put in the
 the string along side ([0005][house]). That way I can have any character
 at all (though I just thinking of char's).

I would still use a portable text format myself. For binary, you should consider rawWrite() and rawRead(). Here is just a start: import std.stdio; void main() { int i = 42; auto file = File("deleteme.bin", "w"); file.rawWrite((&i)[0..1]); } (Aside: The 'b' for binary mode does nothing in POSIX systems; so it's not necessary.) The parameter to rawWrite() above is a nice feature of D: slicing a raw pointer produces a safe slice: http://digitalmars.com/d/2.0/arrays.html <quote> Slicing is not only handy for referring to parts of other arrays, but for converting pointers into bounds-checked arrays: int* p; int[] b = p[0..8]; </quote> For strings (actually arrays), you would need .length and .ptr properties. I've never used it but you might want to consider the serialization library Orange as well: http://www.dsource.org/projects/orange Ali

Jun 30 2011
parent Joel Christensen <joelcnz gmail.com> writes:
Ok, I get you. A whole int*, not one byte of the int* data.

- Joel

On 01-Jul-11 6:07 AM, Ali Çehreli wrote:
 On Fri, 01 Jul 2011 05:28:56 +1200, Joel Christensen wrote:

 Shouldn't file.rawWrite((&i)[0..1]); have [0..4]? Or am I missing some
 thing?

[0..1] follows the regular slicing syntax there: those are element indexes. Since&i is an int*, [0..1] slices the first int. It would be different if it were ubyte* or void*. Ali

Jul 01 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Wed, 29 Jun 2011 19:55:38 +1200, Joel Christensen wrote:

 With the char[], I can't use spaces in it the way I've got it here,
 (like if I tried using a phrase):

There has been a thread very recently about reading strings. Look for the thread "readf with strings" (dated 22-Jun-2011 in my reader). Or, if it works here: http://www.digitalmars.com/webnews/newsgroups.php? art_group=digitalmars.D.learn&article_id=27762 Reading the entire line: string s = chomp(readln()); Kai Meyer suggested parsing the string directly: string[] buffer; int a; float b; string c; buffer = chomp(readln()).split(" "); a = to!(int)(buffer[0]); b = to!(float)(buffer[1]); c = buffer[2..$].join(" "); writef("Read in: '%d' '%f' '%s'\n", a, b, c);
 
 void saveLevel( string fileName ) {
 	int ver = 1;
 	auto house = "two".dup;
 	double rnum = 3.0;
 	
 	{
 		auto fout = File( fileName, "wb"); // open for binary 

 		exit )
 			fout.close;

You are not supposed to need to close the File object yourself. Being a struct, its destructor should be called automatically. Ali
Jun 29 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Thu, 30 Jun 2011 15:52:59 +1200, Joel Christensen wrote:

 I'm thinking more about handling binary files. With the C version I
 would write a int for how many letters in the string, then put in the
 the string along side ([0005][house]). That way I can have any character
 at all (though I just thinking of char's).

I would still use a portable text format myself. For binary, you should consider rawWrite() and rawRead(). Here is just a start: import std.stdio; void main() { int i = 42; auto file = File("deleteme.bin", "w"); file.rawWrite((&i)[0..1]); } (Aside: The 'b' for binary mode does nothing in POSIX systems; so it's not necessary.) The parameter to rawWrite() above is a nice feature of D: slicing a raw pointer produces a safe slice: http://digitalmars.com/d/2.0/arrays.html <quote> Slicing is not only handy for referring to parts of other arrays, but for converting pointers into bounds-checked arrays: int* p; int[] b = p[0..8]; </quote> For strings (actually arrays), you would need .length and .ptr properties. I've never used it but you might want to consider the serialization library Orange as well: http://www.dsource.org/projects/orange Ali
Jun 30 2011
prev sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Fri, 01 Jul 2011 05:28:56 +1200, Joel Christensen wrote:

 Shouldn't file.rawWrite((&i)[0..1]); have [0..4]? Or am I missing some
 thing?

[0..1] follows the regular slicing syntax there: those are element indexes. Since &i is an int*, [0..1] slices the first int. It would be different if it were ubyte* or void*. Ali
Jun 30 2011