- [Instructor] All right, so we talked
about random access in the last video.
So let's get started on changing our application
to use a random access file,
and then to load these locations
for the game on demand.
Now because we're going to have
to change quite a bit of existing code,
and also because it'd be nice
to keep your existing project,
the one we've worked on here to date, as a reference,
what we're going to do is use a new project.
Or rather, we're going to copy this project
and create a back-up version of it.
The easiest way to do that is
to have the project open, which I've got,
just to select the project up here,
and right click, and under Mac I can reveal in Finder,
and on Windows or Linux there should be an option,
something like Open and Explore or Open Folder,
or something like that.
So click on that.
That takes you to the folder where that project is.
So I'm going to copy and paste that,
and you can see in my case, on a Mac,
it's duplicated the folder.
So you'll do something similar for your operating system.
And I'm actually going to change the name of this,
instead of Input Output Copy.
I'm going to change that.
And I'm going to call it something completely different,
Adventure Random.
Because it really is the adventure game
that we've been talking about and working on recently.
And you can see that's been renamed.
Now that I've done that,
I'm going to close this project down,
and then I'm going to navigate to that folder
and open the new project.
And again, we're doing this
so that we can make changes to this code freely,
and we don't have to worry about losing
the original code we had.
And Adventure Random is the name of the project,
so I'm going to open that.
All right, so you can see now that I've got
the adventure random project that I just copied
and duplicated from our previous project open,
and we're going to work on that moving forward now.
Just before we start, let's just make sure
that it still works.
Right click and Run.
I'm running the main, classes main method.
And it looks to me that it's still going to work okay.
But we'll just test this out a little bit.
I'm just going to move this up a little bit
so I can see this a little bit better.
North, Southeast, and quit, that's working fine.
Now we're going to use the locations dot main method
to use random access file to write out the locations.
So our first step is going to be
to write the number of locations to the file.
So I'm going to open our locations class,
and again, we're making the change in the main method
in our locations dot java, so up here.
Our first step, as I mentioned,
is to write out the number of locations to the file.
Now since the file pointer is positioned at byte zero,
when a file is first created or opened,
we don't have the call the sync method
that I talked about in the previous video.
Consequently, it's pretty straight forward.
All you really need to do is with this try,
and we'll change this.
Instead of an object applet stream
it's gonna be random access file.
And of course RAO is equal
to new random access file.
We're going to change the name
of the file as well.
So locations, I'll just call rand dot dat
the second parameter is rwd,
which we'll talk about shortly.
And we'll get rid of this other code.
And the code is raw dot writeInt,
and it's going to be locations dot size.
So again, it's the number of locations
that we've got at the moment
we're writing that to our random access file
locations underscore rand dot dat.
Now code it to RAO here,
because we're going to be loading location on demand
when we run the game.
Now the locations data file
will have to remain open while the application runs.
We're going to call the variable we use
to read the files something different,
so we don't confuse it with the one we're using here,
which is the one that we're writing the locations with.
All right, so the first argument
to random access file is locations
underscore rand dot dat
and clearly that's the name of the file
that we're writing it to,
but this second option here,
well that indicates that we want
to open the file for reading and writing
and also that we want writes to occur synchronously.
Now you can open a file that's read only,
you can also not specify that updates
to the file have to occur synchronously,
but if we do that, and modable threads
can't access the file,
you would actually be responsible
for synchronising the code yourself.
So in this case, it doesn't matter
since only one thread will access the file.
But generally speaking, it's good practise
to have the random access file class
handle the synchronisation, when it does matter.
So, using RWD's, we've used here on line 14.
That's the second argument, is a good idea.
All right, so I've written out the number
of locations, so far, to the file.
What we'll do now is gonna write
the start off set of the locations section.
And once again, since the file pointer
is already positioned correctly,
we can just go ahead and use WriteInt.
So we're gonna type Int index size
is equal to locations dot size times three
times integer dot bytes.
Then we're gonna do int location start
equals int index size plus RAO dot
int file pointer plus integer dot bytes.
Then we're gonna do RAO dot writeInt
and it's gonna be location start.
All right, so each index record,
will contain three integers.
The location ID, the offset for the location,
and the size or length of the location record.
Now we're calculating the index size,
by multiplying the number of locations
by the number of ints contained in each record,
in this case three.
By the number of bytes contained in an integer.
So you can see that we've done that
here on line 16.
So location dot size gives us
the number of locations.
We're multiplying it by three.
And again, the reason we're doing three
is because our index is going to store
the location ID.
Also the offset for the location.
And then the size and length of the location record.
And then we're multiplying that
by the size of an integer.
And we're getting that by using
the integer class dot bytes.
So once we've done that,
on the next line, we then calculate
the current position of the file pointer
to the index size.
To account for the value that we've
already written to the file.
And we also have to account
for the integer, we're about to write to the file,
the location section offset, we just calculated.
So we also have to add the number of bytes
to an integer.
So we're doing that down here, on the end,
the end of that line.
So this will give us the offset for the location section.
Now as an alternative, we could have also added
the index size, to the size of two bytes.
But I like to use the file pointer, wherever possible.
And I suggest that you should probably
do that as well.
And over here, we had cast to an int.
And that's because the file pointer is a long value.
Now we could have written a long,
but we're gonna write ints wherever possible.
And I suggest you do that.
And if you were working with an application
with lots of data, such that the file offsets
could be larger than an int, could hold,
then of course, you'd have to stick
to using longs to make sure you
didn't exceed the maximum size of an int.
All right so we've written out that location start now.
Now the next section in the file is the index.
But before we can write the index,
we have to write the locations.
And that's because each index record
requires the offset for the location.
And, of course, we don't know the offset
until we've written the location.
Now I guess we could write a location
and then write the index record for it.
And then write the next location
and write the index record for it.
And so on, and so forth.
But that would actually involve
a lot of jumping back and forth in the file.
Now a disc access is expensive,
and it's even more expensive
when it's not sequential.
So, instead, what we're gonna do
is write all the locations and then
we'll write the index as a whole.
Now to do that, what we have to do
is build the index in memory
as we write the locations.
Now because we wanna jump back to the file
when we finished writing the locations,
we'll save the current position of the file pointer,
so that we can jump back to it
when we want to write the index,
since we'll write the index after the two
integers we've already written.
We'd be writing it to offset eight.
Which is where the file pointer is currently positioned,
after writing the number of locations
in the location section offset.
All right, we'll do it there,
some code long, index start,
is equal to RAO dot get file pointer.
All right, at this point,
we're ready to write the locations.
Now we've already calculated the offset
of the locations data section.
And we're gonna assign that to a variable
called start pointer, which will update
after writing each location.
And then we'll look through the locations,
write out each location.
Create an index for it.
And add an index record to a map.
Now to do all this, we really need
an index record class.
So we're gonna add a new Java class
called index record to our project.
So let's go ahead and do that.
New class, index record.
So we're going to have two fields here,
the private int stop byte, which I mentioned.
And private int length.
We want a constructor, and the constructor
should accept both parameters,
and save those to the fields.
Now let's also set up parse getters and setters
for this, as well, on both of them.
All right, so there's our class, pretty simple.
Now we said that an index record
could contain the location ID,
start offset, and length.
And when we load the index records into memory,
the location ID will act as a map key.
And that's why we don't have to store it in the class.
In case you're wondering.
All right, so in this cell, go back
to our locations class.
And write out each location.
Now I'm gonna type in all the code first
and then we'll discuss it.
So we're gonna start with our,
and I'll just cut up a little bit
so it's easy to read.
I'll start with an int.
Int start pointer,
and that's equal to location start.
And RAO dot seek stop pointer.
And we're gonna do four location,
location, and locations dot values.
Then we're gonna do RAO dot write int.
And it's gonna be location dot get location ID.
RAO dot write utf.
And that's gonna be descriptions,
so location dot get description.
Then we wanna create a string buddha.
So string buddha buddha is equal to
new string buddha.
And there are gonna be four string direction.
And location dot get exits dot keyset.
If not direction is equal to quit
or equals ignore case Q.
So if it's not quit, we're gonna do builder
dot append direction.
Then we're gonna do builder dot append comma
builder dot append location dot get exits
dot get direction.
And then builder dot append no comma.
Okay, and then just move this up a little bit.
And that's gonna be RAO dot write utf.
And in this case, it'll be builder two string.
And obviously, I'm one level too deep.
That actually should have been there, of course.
We still wanna stay in the four loop.
And we also need to create our index records.
So index record, remember we're writing
the indexes later, but we need to build up
this index in memory, first.
And, so new index record.
The first parameter's gonna be stop pointer.
Then we also wanna store an int.
We'll cast that as an int.
Which will be the RAO dot get file pointer
take start pointer.
Index dot put, we're gonna need to create
that in a minute.
So, location dot get location ID.
And then the actual record, the index record itself.
Then we need to update start pointer.
So start pointer will then equal
cast as an int RAO dot get file pointer,
whatever the current file pointer is.
All right, so let's actually just
add our index field.
I'm gonna go ahead and do that up here.
So that's gonna be private static.
It's gonna be map integer index record
index equal to new.
And it's gonna be linked pash map.
Which obviously makes sense for our application.
Given it's a list of rooms that
are all linked to each other in some way.
So I'll initialise it like that.
And that should mean that the code's ready to go.
And now, we've still got a bit of work
to do on this.
The video's getting a little bit long, here.
So let's pause the video
and continue on this in the next video.