New programmer: help with file reading

Discussion in 'Mac Programming' started by soccersquirt82, Dec 12, 2008.

  1. soccersquirt82 macrumors 6502

    Joined:
    Mar 11, 2008
    #1
    I have a homework assignment for Java and I must read a file that has a list of license plates. If the car goes in, it will have a + before the first letter and if it leaves, it will have a - before. I must print out all the cars left in the garage. The license plate numbers are on different lines. This is what I have:

    Code:
    package garage;
    import java.io.*;
    import java.util.Scanner;
    public class Garage {
    
    	static String[] garagearray = new String[1000];
    	static int maxslot = 0;
    
    	static String readlicense(Scanner scan) {
    		String license = "";
    		license = scan.next();
    		return(license);
    	}
    
    	public static void main(String[] args) {   
    
    		// Declare the filename we will be looking for   
    		String filename = "/Users/crawfordcrenshaw/Documents/garage.txt";   
    		FileInputStream stream;  // the stream we will read from
    
    
    		try {
    			// Open the file.  Reading right to left, we
    			// (1) create a FileInput Stream, pointing to the file; 
    			// (2) assign that stream to the name 'stream'    
    			stream = new FileInputStream(filename); 
    		} catch (IOException e) {   
    			System.out.println("File not found: " + filename);   
    			return;  // abort on error   
    		}
    		Scanner scan = new Scanner(stream);
    
    		// Here the file was opened.  Read in all the characters
    		// Connect a stream reader to the stream. 
    		// read in all the characters until we hit end-of-file, which is   
    		// indicated by a negative return value   
    
    		while(scan.hasNext()){ //looks at every character
    			if (scan.nextByte() == 43) { //the plus character
    				garagearray[maxslot] = readlicense(scan);
    				maxslot++;
    				scan.nextLine();
    			} else if (scan.nextByte() == 45) {
    				String removal = readlicense(scan);
    				for (int i = 0; i < maxslot; ++i) {
    					if (garagearray[i].equals(removal)) {
    						garagearray[i] = "";
    						
    					}
    				}
    				scan.nextLine();
    			} else {
    				scan.nextLine();
    			}
    		}
    
    
    		System.out.println("Here is your garage.  Enjoy!");
    		for (int i = 0; i < maxslot; ++i) {
    			if (!garagearray[i].equals("")) {
    				System.out.println(garagearray[i]);
    			}
    		}
    
    		// close the input file   
    		try {   
    			stream.close();  
    		} catch (IOException e) {     
    			System.out.println("Error closing file: " + filename);    
    			return;  // abort on error   
    		}   
    	}
    }
    
    I get these exceptions:
    Exception in thread "main" java.util.InputMismatchException: For input string: "+63092"
    at java.util.Scanner.nextByte(Scanner.java:1812)
    at java.util.Scanner.nextByte(Scanner.java:1766)
    at garage.Garage.main(Garage.java:39)

    Please help! Keep in mind I am a NEW programmer, so fancy lingo will not work.
     
  2. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    I don't have the file /Users/crawfordcrenshaw/Documents/garage.txt, which makes this a little tough. I'll try to figure out the format, but if data files are needed to run your program, include them.

    -Lee

    Edit: First things first:
    Code:
            static String readlicense(Scanner scan) {
                    String license = "";
                    license = scan.next();
                    return(license);
            }
    
    So you define a string literal, "", that will be using some memory and assign it to license. You then assign the string returned by scan.next() to license, so that old "" it was pointing to is abandoned, and needs to be cleaned up by the garbage collector (there's a chance this literal will be kept in memory by the runtime, but it's still wasteful). You then return the new string. This could be replaced with:
    Code:
    static String readlicense(Scanner scan) {
      return scan.next();
    }
    
    Or just do scan.next() in-line, as having it in a function isn't buying you much.
     
  3. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #3
    Sorry! This is the EXACT file. . . very short:

    +63092
    +92874
    +10093
    +92535
    +85404
    -85404
    -92874
     
  4. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #4
    I'll post again instead of continually editing the same post:
    What does this do? Is the next file a list of "actions"?
    That's to say, does the garage start empty, and when a +<lic#> appears, that means the car has entered, and when a -<lic#> appears, that means the car has exited? What if -abc appears, but there was never a +abc? What is there's a +abc and car abc is already in the garage? How should this behave?

    -Lee
     
  5. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #5
    Yes, that is correct. The teacher told us he will not give us a scenario where you lose a car that was never there.
     
  6. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #6
    In another scenario, there are letters so the program needs to work with letters. Such as:
    +M9H34
     
  7. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #7
    OK, so nextByte is not what you should use, from:
    http://java.sun.com/j2se/1.5.0/docs/api/java/util/Scanner.html#nextByte()
    So nextByte is not getting the raw ascii/UTF-8 value of the next character, but it's getting a type byte, which is a 8-bit signed integer value.

    Try to use: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Scanner.html#next(java.util.regex.Pattern)
    Compile your Pattern at the beginning of your program with:
    http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html#compile(java.lang.String)

    If your Pattern just matches any single character, then scan.next(singleChar) where singleChar is your Pattern will return a string with a single character. Then you can compare that to a string literal with .equals.

    -Lee

    Edit: I didn't enjoy trying to use Pattern, though i'm sure it would be useful. It seems better to just read in a line at a time, and see if the string .startsWith("+"), etc.
     
  8. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #8
    So now that we're past the main problem, there are some other strange things:
    Why are garagearray and maxslot static members of Garage and not local variables in main?

    What happens when you try to put the 1001st car in the garage?

    When you remove an item, you just set it's position to "". You don't "free" a spot up. So if 1 car pulls in and out of the garage 1000 times, the garage is "full" even though there are no cars in it. You then filter empty positions when printing, but this is sort of sloppy.

    You have your filename hardcoded. Are you supposed to accept it at the commandline, or as an argument to your program (this is what i did to play with it)?

    -Lee
     
  9. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #9
    This is my loop:

    Code:
    while(scan.hasNext()){ //looks at every character
    			if (filename.startsWith("+")) { //the plus character
    				garagearray[maxslot] = readlicense(scan);
    				maxslot++;
    				scan.nextLine();
    			} else if (filename.startsWith("-")) {
    				String removal = readlicense(scan);
    				for (int i = 0; i < maxslot; ++i) {
    					if (garagearray[i].equals(removal)) {
    						garagearray[i] = "";
    						
    					}
    				}
    				scan.nextLine();
    			} else {
    				scan.nextLine();
    			}
    		}
    
    It seems that the lines never start with a + or - because it always skips over those lines.
     
  10. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #10
    So why would filename have your file input in it? You never assigned scan.next() or anything to filename. You haven't read anything yet. Read into a String with scan.next(). Then use startsWith on that string. Then you can just use substring to get the rest of the line, after the + or -. Don't worry about readlicense, just get rid of it, it is not saving you any work. Just use substring on the line you read in.

    -Lee
     
  11. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #11
    The program works at the beginning. But when it goes into the for loop to look for the car it was equal to, it crashes on the scan.nextLine();. Why does it crash? And how can I empty the element of the array?

    Code:
    int maxslot=0;
    		
    		while(scan.hasNext()){ //looks at every character
    			String license = scan.next();
    			if (license.startsWith("+")) { //the plus character
    				garagearray[maxslot] = license.substring(1);
    				System.out.println(garagearray[maxslot]);
    				maxslot++;
    				scan.nextLine();
    			 } else if (scan.next().startsWith("-")) {
    				String removal = license.substring(1);
    				for (int i = 0; i < maxslot; ++i) {
    					if (garagearray[i].equals(removal)) {
    						garagearray[i] = "";						
    					}
    				}
    				scan.nextLine();
    			} else {
    				scan.nextLine();
    			}
    		}
    
     
  12. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #12
    Is the order of the cars in the garage important? If not, you could just set garagearray to null (why waste the memory on instantiating and storing an empty string? What's it for?), and search the array for the first null position to add a new car to, instead of just putting it in maxslot. Otherwise, if order does matter or you want to keep the array "condensed" you could go to some extra trouble... this was the code i used for it, but it may be overcomplicated for your needs:
    Code:
    if(i < maxslot-1) System.arraycopy(garagearray,i+1,garagearray,i,garagearray.length-i-1);
    garagearray[garagearray.length-1]=null;
    --maxslot
    break;
    
    Crash is pretty generic. Generally java programs fail when an exception bubbles up past your main function and the JVM catches it. It will normally give you a stack trace with where the original exception was thrown, and each level of the stack that it bubbled up through. What are you getting, specifically?

    Right after I copied out that code, i managed to delete the source file, so I don't have access to my code anymore... however, it seems like you could JUST use scan.nextLine() and assign it's return to license. You should be able to eliminate the else part of your if-than-else-if-than-else block there, so that will be a little cleaner.

    -Lee
     
  13. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #13
    The exception says "No line found," but I still have another line left.
     
  14. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #14
    did you make the change to just use nextLine once per loop, and assigning the result to license?

    -Lee
     
  15. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
    #15
    I changed it a little, but it's now not going into the loop of license.startsWith."+". Why not?

    Code:
    int maxslot = 0;
    		int i = 0;
    
    		while(scan.hasNext()){ //looks at every character
    			String license = scan.nextLine();
    			System.out.println(license);
    			if (license.startsWith("+")) { 
    				if (garagearray[i] == null) { //will fill a null string first
    					garagearray[i] = license.substring(1);
    					break;
    				}
    				if (garagearray[i] != null){
    					garagearray[maxslot] = license.substring(1);
    					maxslot++;
    					break;
    				}
    			} else if (license.startsWith("-")) {
    				String removal = license.substring(1);
    				for (i = 0; i < maxslot; ++i) {
    					if (garagearray[i].equals(removal)) {
    						garagearray[i] = null;						
    					}
    				}
    				break;
    			}
    		}
    
    		System.out.println("Here is your garage.  Enjoy!");
    		for (int s = 0; s < maxslot; ++s) {
    			System.out.println(garagearray[s]);
    			}
    
     
  16. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #16
    You would need to do a loop in the conditional when startsWith("+") is true. You can loop to garagearray.length, you will eventually find a null. You can incremement maxslot if the position you find the null is equal to maxslot.

    -Lee
     
  17. soccersquirt82 thread starter macrumors 6502

    Joined:
    Mar 11, 2008
  18. prostuff1 macrumors 65816

    prostuff1

    Joined:
    Jul 29, 2005
    Location:
    Don't step into the kawoosh...
    #18
    I'm not sure if your allowed to but i would look into using arraylist. The documentation for it can be found at the link below.

    http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html

    I would read in one line at a time and check the first char to see if it a plus or a minus sisn. If plus then call the arraylist.add("") and if a minus first search the arraylist and call the arraylist.remove("') function.

    Hope that helps
     

Share This Page