Basic Save File IO Questions "Dangling meta character '+' near index 0"

Hi!

So I’ve been trying the brute force method of creating save files for my text adventure using .txt files, but I keep getting errors when I try to load the game. Currently there are 3 .txt files in my source folder in Eclipse, which I realize might be a bit of a weird place to put them as they would be bundled in with my .jar file when exported, but anyway when I try to load a game from the compiler it fails and gives me an exception of “Exception in thread “AWT-EventQueue-0” java.util.regex.PatternSyntaxException: Dangling meta character ‘+’ near index 0”, though curiously, saving seems to work fine (at least in that exceptions are not thrown when the save function is called).

My save and load methods are (Please don’t be intimidated, a good portion of these are just me concatenating/digesting a string of all the class variables I’m keeping track of):


String fileName1 = "save1.txt";
	String fileName2 = "save2.txt";
	String fileName3 = "save3.txt";
	Saver saver1 = new Saver(fileName1, false);
	Saver saver2 = new Saver(fileName2, false);
	Saver saver3 = new Saver(fileName3, false);
	int fileChosen = 1;
	String saveFileToParse = "";
	String saveFileToSave = "";

// Let's try building the methods in general
	void loadGame (int fileNumber)
	{
		// First, return the string that contains the save data
		if (fileNumber == 1)
		{
			saveFileToParse = saver1.load();
		}
		if (fileNumber == 2)
		{
			saveFileToParse = saver2.load();
		}
		if (fileNumber == 3)
		{
			saveFileToParse = saver2.load();
		}
		
		// TODO Add code to parse the string made with the saveGame method
		String[] parts = saveFileToParse.split("+");
		int number = 0;
		scene = Integer.parseInt(parts[number]); 
		number++;// THIS IS AN INT
		lastInput = Integer.parseInt(parts[number]); 
		number++;// THIS IS AN INT
		lastLargestChoice = Integer.parseInt(parts[number]); 
		number++;// THIS IS AN INT
		windOpinion = Integer.parseInt(parts[number]); 
		number++;// THIS IS AN INT
		hardKnockOpinion = Integer.parseInt(parts[number]); 
		number++;// THIS IS AN INT
		blueBloodOpinion = Integer.parseInt(parts[number]); 
		number++;// THIS IS AN INT
		  uraOpinion = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  seasonsOpinion = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  room = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  largestChoice = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT //TODO, be very careful with this and
						// input
		  health = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  time = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  internalTime  = Integer.parseInt(parts[number]); 
			number++; // THIS IS AN INT
		  race = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  name  = parts[number];
		  number++;// THIS IS A STRING
		  firstTime  = parts[number].equalsIgnoreCase("true");
		  number++;// THIS IS A BOOLEAN
		  justEntered = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  isTalking = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  moved   = parts[number].equalsIgnoreCase("true");
		  number++;  // THIS IS A BOOLEAN
		  finishedTalking  = parts[number].equalsIgnoreCase("true");
		  number++;   // THIS IS A BOOLEAN
		  tripped   = parts[number].equalsIgnoreCase("true");
		  number++;  // THIS IS A BOOLEAN
		  windQuest  = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  uraQuest  = parts[number].equalsIgnoreCase("true");
		  number++;   // THIS IS A BOOLEAN
		  uraQuest2 = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  hardKnockQuest = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  bluebloodQuest = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  mainQuest = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  uraRomance = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  hardKnockRomance  = parts[number].equalsIgnoreCase("true");
		  number++;   // THIS IS A BOOLEAN
		  liedToUra = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  wrongBottle = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  realName = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  yourWounds = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  labDoorWedged = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  trainingRoomDoorWedged = parts[number].equalsIgnoreCase("true");
		  number++;   // THIS IS A BOOLEAN
		  seenWind = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  sceneAboutToEnd = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  hardKnockKnowsAboutBlueBlood = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  spokenToHardKnockBefore = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  hardKnockCornered = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  convincedWind = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  convincedHardKnock = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  convincedUra = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  threwShieldAmulet = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  savedUra  = parts[number].equalsIgnoreCase("true");
		  number++;   // THIS IS A BOOLEAN
		  blackedOut = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  introPlayed = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  rockOut = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  puppyPresent = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  input = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  hardKnock = Integer.parseInt(parts[number]); 
			number++;    // THIS IS AN INT
		  wind  = Integer.parseInt(parts[number]); 
			number++;   // THIS IS AN INT
		  blueBlood  = Integer.parseInt(parts[number]); 
			number++;  // THIS IS AN INT
		  ura = Integer.parseInt(parts[number]); 
			number++;   // THIS IS AN INT
		  pause = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  exitLoop = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  firstRound = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  hidInformation = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  searchedFront = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  searchedBack = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  searchedLeft = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  searchedRight = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  mushroomLit = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  prosthesis = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  healingPotion = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  halfHealingPotion = parts[number].equalsIgnoreCase("true");
		  number++;  // THIS IS A BOOLEAN
		  shieldAmulet = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  letterOpener = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  scalpel = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  axe = parts[number].equalsIgnoreCase("true");
		  number++;     // THIS IS A BOOLEAN
		  spikedShoes = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  glowLamp = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
		  mushroom = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
	      flask = parts[number].equalsIgnoreCase("true");
		  number++;    // THIS IS A BOOLEAN
	      combatOptionsCount = Integer.parseInt(parts[number]); 
			number++;     // THIS IS AN INT
	      fightMessage = parts[number];
	      number++;// THIS IS A STRING
	      combatOptions[0]  = parts[number];
	      number++;   // THIS IS A STRING
	      combatOptions[1] = parts[number];
	      number++;    // THIS IS A STRING
	      combatOptions[2] = parts[number];
	      number++;    // THIS IS A STRING
	      combatOptions[3] = parts[number];
	      number++;    // THIS IS A STRING
	      combatOptions[4] = parts[number];
	      number++;// THIS IS A STRING
		
	}
	
	void saveGame (int fileNumber)
	{
		// TODO Add code to create the save file string and store it in the
		// String saveFileToSave
		// Plus signs will act as delimiters
		saveFileToSave = 
		scene + "+"// THIS IS AN INT
		+ lastInput + "+"// THIS IS AN INT
		+ lastLargestChoice + "+"// THIS IS AN INT
		+ windOpinion + "+"// THIS IS AN INT
		+ hardKnockOpinion + "+"// THIS IS AN INT
		+ blueBloodOpinion + "+"// THIS IS AN INT
		+ uraOpinion + "+"// THIS IS AN INT
		+ seasonsOpinion + "+"// THIS IS AN INT
		+ room + "+"// THIS IS AN INT
		+ largestChoice + "+"// THIS IS AN INT //TODO, be very careful with
								// this and input
		+ health + "+"// THIS IS AN INT
		+ time + "+"// THIS IS AN INT
		+ internalTime + "+"// THIS IS AN INT
		+ race + "+"// THIS IS AN INT
		+ name + "+" // THIS IS A STRING
		+ firstTime + "+" // THIS IS A BOOLEAN
		+ justEntered + "+" // THIS IS A BOOLEAN
		+ isTalking + "+" // THIS IS A BOOLEAN
		+ moved + "+" // THIS IS A BOOLEAN
		+ finishedTalking + "+" // THIS IS A BOOLEAN
		+ tripped + "+" // THIS IS A BOOLEAN
		+ windQuest + "+" // THIS IS A BOOLEAN
		+ uraQuest + "+" // THIS IS A BOOLEAN
		+ uraQuest2 + "+" // THIS IS A BOOLEAN
		+ hardKnockQuest + "+" // THIS IS A BOOLEAN
		+ bluebloodQuest + "+" // THIS IS A BOOLEAN
		+ mainQuest + "+" // THIS IS A BOOLEAN
		+ uraRomance + "+" // THIS IS A BOOLEAN
		+ hardKnockRomance + "+" // THIS IS A BOOLEAN
		+ liedToUra + "+" // THIS IS A BOOLEAN
		+ wrongBottle + "+" // THIS IS A BOOLEAN
		+ realName + "+" // THIS IS A BOOLEAN
		+ yourWounds + "+" // THIS IS A BOOLEAN
		+ labDoorWedged + "+" // THIS IS A BOOLEAN
		+ trainingRoomDoorWedged + "+" // THIS IS A BOOLEAN
		+ seenWind + "+" // THIS IS A BOOLEAN
		+ sceneAboutToEnd + "+" // THIS IS A BOOLEAN
		+ hardKnockKnowsAboutBlueBlood + "+" // THIS IS A BOOLEAN
		+ spokenToHardKnockBefore + "+" // THIS IS A BOOLEAN
		+ hardKnockCornered + "+" // THIS IS A BOOLEAN
		+ convincedWind + "+" // THIS IS A BOOLEAN
		+ convincedHardKnock + "+" // THIS IS A BOOLEAN
		+ convincedUra + "+" // THIS IS A BOOLEAN
		+ threwShieldAmulet + "+" // THIS IS A BOOLEAN
		+ savedUra + "+" // THIS IS A BOOLEAN
		+ blackedOut + "+" // THIS IS A BOOLEAN
		+ introPlayed + "+" // THIS IS A BOOLEAN
		+ rockOut + "+" // THIS IS A BOOLEAN
		+ puppyPresent + "+" // THIS IS A BOOLEAN
		+ input + "+"// THIS IS AN INT
		+ hardKnock + "+"// THIS IS AN INT
		+ wind + "+"// THIS IS AN INT
		+ blueBlood + "+"// THIS IS AN INT
		+ ura + "+"// THIS IS AN INT
		+ pause + "+" // THIS IS A BOOLEAN
		+ exitLoop + "+" // THIS IS A BOOLEAN
		+ firstRound + "+" // THIS IS A BOOLEAN
		+ hidInformation + "+" // THIS IS A BOOLEAN
		+ searchedFront + "+" // THIS IS A BOOLEAN
		+ searchedBack + "+" // THIS IS A BOOLEAN
		+ searchedLeft + "+" // THIS IS A BOOLEAN
		+ searchedRight + "+" // THIS IS A BOOLEAN
		+ mushroomLit + "+" // THIS IS A BOOLEAN
		+ prosthesis + "+" // THIS IS A BOOLEAN
		+ healingPotion + "+"// THIS IS A BOOLEAN
		+ halfHealingPotion + "+"// THIS IS A BOOLEAN
		+ shieldAmulet + "+"// THIS IS A BOOLEAN
		+ letterOpener + "+"// THIS IS A BOOLEAN
		+ scalpel + "+"// THIS IS A BOOLEAN
		+ axe + "+" // THIS IS A BOOLEAN
		+ spikedShoes + "+"// THIS IS A BOOLEAN
		+ glowLamp + "+"// THIS IS A BOOLEAN
		+ mushroom + "+"// THIS IS A BOOLEAN
	    + flask + "+"// THIS IS A BOOLEAN
	    + combatOptionsCount + "+" // THIS IS AN INT
	    + fightMessage + "+" // THIS IS A STRING
	    + combatOptions[0] + "+" // THIS IS A STRING
	    + combatOptions[1] + "+" // THIS IS A STRING
	    + combatOptions[2] + "+" // THIS IS A STRING
	    + combatOptions[3] + "+" // THIS IS A STRING
	    + combatOptions[4]; // THIS IS A STRING
	    
		if (fileNumber == 1)
		{
			try
			{
			saver1.saveToFile(saveFileToSave);
			}
			catch (IOException e)
			{
			System.out.println("File Not Found!");
			// TODO, much, much more robust error handling than this.
			}
		}
		if (fileNumber == 2)
		{
			try
			{
			saver2.saveToFile(saveFileToSave);
			}
			catch (IOException e)
			{
			System.out.println("File Not Found!");
			// TODO, much, much more robust error handling than this.
			}
		}
		if (fileNumber == 3)
		{
			try
			{
			saver3.saveToFile(saveFileToSave);
			}
			catch (IOException e)
			{
			System.out.println("File Not Found!");
			// TODO, much, much more robust error handling than this.
			}
		}
	}
	
	

And my file IO class looks like:


package woundedTestPackage;

import java.util.Scanner;
import java.io.File; //A different pre-defined class for manipulating files
import java.io.FileNotFoundException; //MUST use error checking
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.IOException;


public class Saver {
	
	private String path;
	private String saveData;
	private boolean appendToFile = false;
	private Scanner inputStream;
	
	public Saver(String filePath)
	{
	  path = filePath;
	}
	
	public Saver(String filePath, boolean appendValue)
	{
	  path = filePath;
	  appendToFile = appendValue;
	}
	
	public void saveToFile (String textLine) throws IOException 
	{
		FileWriter save = new FileWriter(path, appendToFile);
		PrintWriter saveLine = new PrintWriter(save);
		saveLine.printf("%s" + "%n" , textLine);
		saveLine.close();
	}
	
	public String load()
	{
		try //RUNTIME error checking structure
		{
			inputStream = new Scanner(new File(path)); //Scanner object instance gets input
		}
		catch (FileNotFoundException e) // what error to catch
		{
			System.out.println("File not found?");
			System.exit(0); //DO NOT CONTINUE WITH REST OF PROGRAM
		}
		saveData = inputStream.nextLine();
		return saveData;
	}

}


Have I formatted my save file incorrectly for the load system I’ve built? Should I use a different delimiter in my files? I would really appreciate any assistance that could be provided.


So, I entered + as an escape sequence and it works now… huh. Okay then.

So your proble is solved?

Well… now that I’ve been examining it more, I’ve noted an issue. because some of the variables are initialized as empty Strings at the start of my program, the function I used to split my string into an array does not create an array of the proper length at the end. the +++ is read as noise instead of 3 extra strings, and thus an exception is thrown. I may have a plan for it though, a try catch block at the end of my code like this:


try
	     {
	      combatOptions[2] = parts[number];
	      number++;    // THIS IS A STRING
	      combatOptions[3] = parts[number];
	      number++;    // THIS IS A STRING
	      combatOptions[4] = parts[number];
	      number++;// THIS IS A STRING
	     }
	     catch (Exception e)
	     {
	    	 combatOptions[2] = "";
		      combatOptions[3] = "";
		      combatOptions[4] = "";
	     }