File reading for save function

I need to figure out how to differentiate between integers in my save file:


0,595,1
0,611,0
0,627,2
0,643,2
0,659,2
0,675,2

I want this to translate to:


x,y,blockType

each line of numbers represent a new block to be spawn when this file is called. I just need to figure out how to tell which number goes for which variable. The x,y,and blocktype are all stored in arraylists and can already be used to spawn blocks.

here is my reading files code so far:

public static void ReadFile(String path){
	        try {
	            FileInputStream fStream = new FileInputStream(path);
	            BufferedReader in = new BufferedReader(new InputStreamReader(fStream));
	            while (in.ready()) {
	                System.out.println(in.readLine());
	            }
	            in.close();
	        } catch (IOException e) {
	            System.out.println("File input error");
	        }
	    }

thanks for your help

I’d just ignore the possibility that the line is formatted incorrectly. Then simply throw the line into a StringTokenizer and get the 3 ints you need.


StringTokenizer tokenizer = new StringTokenizer(line, ",");
if(tokenizer.countTokens() >= 3) {
   list1.add(Interger.valueOf(tokenizer.nextToken());
   // etc, etc.
}

You could also take the approach of ensuring that each int is what you want, then just parsing out the ints. This is, in my opinion, a waste as you’re unlikely to want to edit large maps by hand.


// Text file
x=0 y=595 id=1

Or, if you want to save space on map sizes you could just read/write integers to the file in sets of three. First three integers are a block and so on.

Just wrote this up hope it’s what you’re looking for ^^
(Documented so you know what’s occurring ^
^)


	LinkedList<Block> blocks = new LinkedList<Block>();

	public void loadChunk(String path2File) throws FileNotFoundException {
		FileReader fr = new FileReader(new File(path2File));
		BufferedReader br = new BufferedReader(fr);

		// the line being read
		String line = "";

		try {
			while ((line = br.readLine()) != null) {

				// line will be read as: 0,595,1

				// turn the line into 3 strings
				// each letter seperated by a comma

				String[] dataArray = line.split(",");

				// dataArray[0] = 0; (X)
				// dataArray[1] = 595; (Y)
				// dataArray[2] = 1; (BlockType)

				// CASTING FROM STRING TO INTEGER
				int x = Integer.parseInt(dataArray[0]);
				int y = Integer.parseInt(dataArray[1]);
				int blockType = Integer.parseInt(dataArray[2]);

				// add the block to the block list & load another
				blocks.add(new Block(x, y, blockType));
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

What you are looking for is; regular expressions: http://docs.oracle.com/javase/tutorial/essential/regex/

I’m getting this error:

Exception in thread "Thread-3" java.lang.OutOfMemoryError: Java heap space
	at sqr.gui.org.MainMenu.LoadGame(MainMenu.java:56)
	at sqr.main.org.BlockSpawn.<init>(BlockSpawn.java:95)
	at sqr.main.org.Game.render(Game.java:236)
	at sqr.main.org.Game.run(Game.java:161)
	at java.lang.Thread.run(Unknown Source)

Is this because i’m trying to load too much it is about 450 blocks

Could you post line # 56 in MainMenu.Java?

at sqr.gui.org.MainMenu.LoadGame(MainMenu.java:56)

Would be better if you could post the whole “Load Game” method :slight_smile:

Never mind i fixed it thanks for the help guys
;D

In your block class, it might just be best to have the parsing of the string in there as a constructor


public class Block
{
   int x, y, blocktype;

   public Block(String data)
   {
       //we make sure to use regex so add a little bit of lenience to parsing
       String[] parsedData = data.split("/[, ]+/");

       this.x = Integer.parseInt(parsedData[0]);
       this.y = Integer.parseInt(parsedData[1]);
       this.blocktype = Integer.parseInt(parsedData[2]);
   }
}

If ever it throws an exception, then we just won’t add the block to your array and the garbage collector will pick it up.


ArrayList<Block> blocks = new ArrayList<Block>();

try (BufferedReader br = new BufferedReader(new FileReader(filepath)))
{
    String line;
    while ((line = br.readLine()) != null)
    {
        try
        {
            Block b = new Block(line);
            blocks.add(b);
        }
    }
}


Thanks to try-with-resources, we can easily jump through a bufferedreader and have it automatically close when we’re done. It keeps the code looking a lot cleaner.

StringTokenizer sounds good… but I would do this because I always forget about it:

for (String line : fileAsString.replace("\r", “”).split("\n") {
String[] nums = line.split(",");
Block b = new Block(Long.parseLong(nums[0]), Long.parseLong(nums[1]), Long.parseLong(nums[2]));
blockHandler.handleBlock(b);
}

@nhydock, why build lenience into file reading. Keep it strict and reject all deviation, I say!

Why did I quote myself… I thought I was editing my last post ???

I agree - just ignoring errors and hoping they go away without affecting the rest of the program is just madness.

Building robust code is not about hiding errors, but finding out what caused them.

If it’s a save function, then the format of the save file should be well known. As such, any deviation from the well known pattern is likely to indicate either a failure to correctly save the data or else a failed edit by an outside entity. If you’re worried about the first of the two options, then you need to identify the failure to save at save time rather than load time. There are several methods by which you can do this (Saving then loading and checking if the load resulted in the same game state, creating a check-sum or something off the expected save file, etc…)

The only reason you’d need a robust loader is if you support multiple versions of the load function based on previous versions of the save function (Backwards compatibility). In that case, you only need enough information to figure out which loader you should use rather than making a robust error checker that allows you to do it.