Home » Local Data Storage 8 – Random Access Files with Java

Share This Post

Java / Main Slider / Tutorial

Local Data Storage 8 – Random Access Files with Java

Random Access Files with Java

Working with Java and Files Tutorial Trail
Left ArrowSerialized XML to FilesSQLite Databaseright arrow

Random Access Files(API) (RAF) in Java are super easy to use. Use an RAF when you are doing more database-like operations vs document-like operations. With an RAF you can move to any location in the file based on the byte number.  Then read or write primitives and Strings. You can also read and write arrays of bytes. It would be easy enough to write a set of primitives associated with an object which is the object’s state, then reload and rebuild the object later.

Six Examples

So in this article, I will give you 6 examples of storing and reading – one, two and three dimensioned arrays of integers. The first 3 examples simply generate random numbers in arrays then write them to an RAF. They then read the whole file back displaying it at the console. The next 3 read a single integer from a single location within the file and then multiply it by 5 and put it back in the file. They then read it back from the file to show that it had been read, changed stored and re-read from the file at the given locations.

Storing Strings

If you store a string in a random access file it should probably be cropped with character space filled to a given length for something like arrays or records or object state. You could also seek (move the pointer) to the position for next write operation after writing a String.  This is similar to how strings are stored in databases. Otherwise, odd length strings screw up the location math.

Storing Object States

This would be more complex than my current examples, but you could write a custom method that, given an expected object, reads state fields directly or with getter methods and writes out a series of primitives and strings as a record for that object to the RAF.  Then a custom read method would read in each state one at a time, instantiating a new object and setting fields or using getters to restore the state for each object in the array.  And if you wanted to access objects by element number consider this. You would have to carefully calculate the length of each primitive or string to store and come up with total bytes for that record. This gives you a basis to seek each record out.  If I get time I will upgrade this article to include such an example later in the year.

My Immediate Needs for RAF

I need a way to store map data for each layer of game maps. These maps are grid tile-based maps. If you look at the image for this article you will see an overworld view of a game I began to work on some 15 years ago. I didn’t get far, I only did the overworld map, cave map, dungeon map and mine map. And it was only a prototype.  This map had 2 layers. The terrain layer and the layer for city, roads, hills, mountains, rivers, mines, dungeons, caves entrances.  If there were mobs it might have another layer for that.

Each tile type could have a unique integer ID. So a map layer consists of a grid (2D Array) of map tile ID’s.  And two or more layers is effectively a 3D Array.  Using random access files an editor could be made to edit very large maps, 1000×1000 or the hard disk space is the limit.  An editor might have in view only 20×20 tiles at a time.  And as you plot/paint terrain types around the data on disk is changed right where needed in the file.  there is no need to scan through the file to the point of change or load and save entire files.

3D Mesh Surface

3D Mesh Surface

3D Surface using Java is the 2nd use. This surface is a grid of elevation data. it will be a snap to store the data which is in a 2D Array to an RAF using the example code below. I can then make an editor which allows the user to raise and lower points on the surface and then save the surface. The surface could then be loaded into a game.

Finally

You can put anything anywhere in an RAF. You simply have to keep track of the size of the data, where it is at and be careful not to overwrite other data unintentionally.  If you have a data structure that must grow in size then things become a bit more complex to handle. One way to handle this is with Linked List. A Linked list can quickly be made into a Stack or Queue.  Problems might arise similar to memory heaps, where you have unused bytes here and there and at some point have to defrag the file.  One thing to note about RAF files is that primitives are stored using the same bytes that represent them in ram, meaning much more compact than their string representations. Thus conserving disk space.

Storing Data

A simple array of Integers

import java.io.*;

public class ReadWriteArrayRandomAccessFile {
 RandomAccessFile raf = null;
 int[] integers = new int[100];
 int min = 10;
 int max = 200;
 public ReadWriteArrayRandomAccessFile(){
  try{
  	  raf = new RandomAccessFile("array.txt", "rw");
      makeRandomIntegers();
      writeIntegers();
      raf.seek(0);
      readIntegers();
  }catch(Exception e){
  	  e.printStackTrace();
  }
 }
 public void makeRandomIntegers(){
  for(int i=0;i<100;i++)
   integers[i]=min + (int)(Math.random() * ((max - min) + 1));
 }
 public void writeIntegers(){
  try{
   for(int i=0;i<100;i++)
    raf.writeInt(integers[i]);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 public void readIntegers(){
  int integer=0;
  try{
   for(int i=0;i<100;i++){
    integer = raf.readInt();
    System.out.println("#"+i+" "+integer);
   }
  }catch(Exception e){
  	e.printStackTrace();  
  }
 }
 public static void main(String args[]){
  new ReadWriteArrayRandomAccessFile();	 
 }
}

Two-dimensioned array of Integers

import java.io.*;

public class ReadWriteArrayRandomAccessFile2 {
 RandomAccessFile raf = null;
 int[][] integers = new int[25][25];
 int min = 10;
 int max = 200;
 public ReadWriteArrayRandomAccessFile2(){
  try{
  	  raf = new RandomAccessFile("array2.txt", "rw");
      makeRandomIntegers();
      writeIntegers();
      raf.seek(0);
      readIntegers();
  }catch(Exception e){
  	  e.printStackTrace();
  }
 }
 public void makeRandomIntegers(){
  for(int x=0;x<25;x++)
   for(int y=0;y<25;y++)
    integers[x][y] = min + (int)(Math.random() * ((max - min) + 1));
 }
 public void writeIntegers(){
  try{
   for(int x=0;x<25;x++)
    for(int y=0;y<25;y++)
     raf.writeInt(integers[x][y]);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 public void readIntegers(){
  int integer=0;
  try{
   for(int x=0;x<25;x++)
    for(int y=0;y<25;y++){
     integer = raf.readInt();
     System.out.println("x:"+x+" y:"+y+" val:"+integer);
    }
  }catch(Exception e){
  	e.printStackTrace();  
  }
 }
 public static void main(String args[]){
  new ReadWriteArrayRandomAccessFile2();	 
 }
}

Three-dimensioned array of Integers

import java.io.*;

public class ReadWriteArrayRandomAccessFile3 {
 RandomAccessFile raf = null;
 int[][][] integers = new int[10][10][10];
 int min = 10;
 int max = 200;
 public ReadWriteArrayRandomAccessFile3(){
  try{
  	  raf = new RandomAccessFile("array3.txt", "rw");
      makeRandomIntegers();
      writeIntegers();
      raf.seek(0);
      readIntegers();
  }catch(Exception e){
  	  e.printStackTrace();
  }
 }
 public void makeRandomIntegers(){
  for(int x=0;x<10;x++)
   for(int y=0;y<10;y++)
    for(int z=0;z<10;z++)
     integers[x][y][z] = min + (int)(Math.random() * ((max - min) + 1));
 }
 public void writeIntegers(){
  try{
   for(int x=0;x<10;x++)
    for(int y=0;y<10;y++)
     for(int z=0;z<10;z++)
      raf.writeInt(integers[x][y][z]);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 public void readIntegers(){
  int integer=0;
  try{
   for(int x=0;x<10;x++)
    for(int y=0;y<10;y++)
     for(int z=0;z<10;z++){
      integer = raf.readInt();
      System.out.println("x:"+x+" y:"+y+" z:"+z+" val:"+integer);
     }
  }catch(Exception e){
  	e.printStackTrace();  
  }
 }
 public static void main(String args[]){
  new ReadWriteArrayRandomAccessFile3();	 
 }
}

Read, Update, Write

Integer

import java.io.*;

public class ReadWriteArrayRandomAccessFile4 {
 RandomAccessFile raf = null;
 int[] integers = new int[100];
 int min = 10;
 int max = 200;
 public ReadWriteArrayRandomAccessFile4(){
  int integer=0;
  try{
  	  raf = new RandomAccessFile("array4.txt", "rw");
      makeRandomIntegers();
      writeIntegers();
      raf.seek(0);
      integer=readInt(40);
      System.out.println("Read Int Loc 40:"+integer);
      integer*=5;
      System.out.println("Multiply Int by 5 and write it back to Loc 40");
      writeInt(40,integer);
      integer=readInt(40);
      System.out.println("Read New Stored Int Loc 40:"+integer);   
  }catch(Exception e){
  	  e.printStackTrace();
  }
 }
 public void makeRandomIntegers(){
  for(int i=0;i<100;i++)
   integers[i]=min + (int)(Math.random() * ((max - min) + 1));
 }
 public void writeIntegers(){
  try{
   for(int i=0;i<100;i++)
    raf.writeInt(integers[i]);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 public int readInt(int loc){
  int integer=0;
  try{	  
   raf.seek(loc*4);  // 4 bytes per int
   integer = raf.readInt();
  }
  catch(Exception e){
  	e.printStackTrace();  
  } 
  return integer;
 }
 public void writeInt(int loc, int integer){
   try{
    raf.seek(loc*4); // 4 bytes per int
    raf.writeInt(integer);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 
 public static void main(String args[]){
  new ReadWriteArrayRandomAccessFile4();	 
 }
}

Two-D Integer

import java.io.*;

public class ReadWriteArrayRandomAccessFile5 {
 RandomAccessFile raf = null;
 int[][] integers = new int[25][25];
 int min = 10;
 int max = 200;
 public ReadWriteArrayRandomAccessFile5(){
  int integer=0;
  try{
  	  raf = new RandomAccessFile("array5.txt", "rw");
      makeRandomIntegers();
      writeIntegers();
      raf.seek(0);
      integer=readInt(15,12);
      System.out.println("Read Int Loc 15,12:"+integer);
      print3x3(15,12);
      integer*=5;
      System.out.println("Multiply Int by 5 and write it back to Loc 15,12");
      writeInt(15,12,integer);
      integer=readInt(15,12);
      System.out.println("Read New Stored Int Loc 15,12:"+integer);
      print3x3(15,12);
  }catch(Exception e){
  	  e.printStackTrace();
  }
 }
 public void makeRandomIntegers(){
  for(int x=0;x<25;x++)
   for(int y=0;y<25;y++)
    integers[x][y] = min + (int)(Math.random() * ((max - min) + 1));
 }
 public void writeIntegers(){
  try{
   for(int x=0;x<25;x++)
    for(int y=0;y<25;y++)
     raf.writeInt(integers[x][y]);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 public void readIntegers(){
  int integer=0;
  try{
   for(int x=0;x<25;x++)
    for(int y=0;y<25;y++){
     integer = raf.readInt();
     System.out.println("x:"+x+" y:"+y+" val:"+integer);
    }
  }catch(Exception e){
  	e.printStackTrace();  
  }
 }
 public int readInt(int x, int y){
  int integer=0;
  try{	  
   raf.seek((x*4*25)+(y*4));  // 4 bytes per int, 25*4 bytes per x or column
   integer = raf.readInt();
  }
  catch(Exception e){
  	e.printStackTrace();  
  } 
  return integer;
 }
 public void writeInt(int x, int y, int integer){
   try{
    raf.seek((x*4*25)+(y*4)); // 4 bytes per int, 25*4 bytes per x or column
    raf.writeInt(integer);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 
 public void print3x3(int x, int y){
  System.out.println(""+readInt(x-1,y-1)+" "+readInt(x,y-1)+" "+readInt(x+1,y-1));
  System.out.println(""+readInt(x-1,y)+" "+readInt(x,y)+" "+readInt(x+1,y));
  System.out.println(""+readInt(x-1,y+1)+" "+readInt(x,y+1)+" "+readInt(x+1,y+1));
 }
 public static void main(String args[]){
  new ReadWriteArrayRandomAccessFile5();	 
 }
}

Three-D Integer

import java.io.*;

public class ReadWriteArrayRandomAccessFile6 {
 RandomAccessFile raf = null;
 int[][][] integers = new int[25][25][25];
 int min = 10;
 int max = 200;
 public ReadWriteArrayRandomAccessFile6(){
  int integer=0;
  try{
  	  raf = new RandomAccessFile("array6.txt", "rw");
      makeRandomIntegers();
      writeIntegers();
      raf.seek(0);
      integer=readInt(3,15,12);
      System.out.println("Read Int Layer 3 Loc 15,12:"+integer);
      print3x3x3(3,15,12);
      integer*=5;
      System.out.println("Multiply Int by 5 and write it back to Layer 3 Loc 15,12");
      writeInt(3,15,12,integer);
      integer=readInt(3,15,12);
      System.out.println("Read New Stored Int Layer 3 Loc 15,12:"+integer);
      print3x3x3(3,15,12);
  }catch(Exception e){
  	  e.printStackTrace();
  }
 }
 public void makeRandomIntegers(){
  for(int layer=0;layer<25;layer++)
   for(int x=0;x<25;x++)
    for(int y=0;y<25;y++)
     integers[layer][x][y] = min + (int)(Math.random() * ((max - min) + 1));
 }
 public void writeIntegers(){
  try{
   for(int layer=0;layer<25;layer++)	  
    for(int x=0;x<25;x++)
     for(int y=0;y<25;y++)
      raf.writeInt(integers[layer][x][y]);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }

 public int readInt(int layer, int x, int y){
  int integer=0;
  try{	  
   // 4 bytes per int, 25*4 bytes per x or column, 25*25*4 per layer	  
   raf.seek((layer*4*25*25)+(x*4*25)+(y*4));  
   integer = raf.readInt();
  }
  catch(Exception e){
  	e.printStackTrace();  
  } 
  return integer;
 }
 public void writeInt(int layer, int x, int y, int integer){
   try{
    // 4 bytes per int, 25*4 bytes per x or column, 25*25*4 per layer
   	raf.seek((layer*4*25*25)+(x*4*25)+(y*4)); 
    raf.writeInt(integer);
   }catch(Exception e){
  	 e.printStackTrace();  
   }
 }
 
 public void print3x3x3(int l, int x, int y){
  System.out.print(""+readInt(l-1, x-1,y-1)+" "+readInt(l-1, x,y-1)+" "+readInt(l-1, x+1,y-1));
  System.out.print("  "+readInt(l,x-1,y-1)+" "+readInt(l,x,y-1)+" "+readInt(l,x+1,y-1));
  System.out.println("  "+readInt(l+1,x-1,y-1)+" "+readInt(l+1,x,y-1)+" "+readInt(l+1,x+1,y-1));
  
  System.out.print(""+readInt(l-1,x-1,y)+" "+readInt(l-1,x,y)+" "+readInt(l-1,x+1,y));
  System.out.print("  "+readInt(l,x-1,y)+" "+readInt(l,x,y)+" "+readInt(l,x+1,y));
  System.out.println("  "+readInt(l+1,x-1,y)+" "+readInt(l+1,x,y)+" "+readInt(l+1,x+1,y));
  
  System.out.print(""+readInt(l-1,x-1,y+1)+" "+readInt(l-1,x,y+1)+" "+readInt(l-1,x+1,y+1));
  System.out.print("  "+readInt(l,x-1,y+1)+" "+readInt(l,x,y+1)+" "+readInt(l,x+1,y+1));
  System.out.println("  "+readInt(l+1,x-1,y+1)+" "+readInt(l+1,x,y+1)+" "+readInt(l+1,x+1,y+1));
 }
 public static void main(String args[]){
  new ReadWriteArrayRandomAccessFile6();	 
 }
}

Share This Post

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>