Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Assignment : Data that is written to a file is commonly structured as fields and

ID: 3859706 • Letter: A

Question

Assignment:

Data that is written to a file is commonly structured as fields and records. In file terminol­ogy, a field is an individual piece of data, such as a person’s name or telephone number. A record is a collection of fields pertaining to a single item. For example, a record might con­sist of a specific person’s name, age, address, and telephone number.

Quite often you can save the contents of an object as a record in a file. You do this by writ­ing each of the object’s fields to the file, one after the other. When you have saved all of the object’s fields, a complete record has been written. When the fields from multiple objects have been saved, then multiple records have been written to the file.

Random access files are particularly useful for storing and retrieving records. However, the sizes of the items stored in a random access file must be known in order to calculate the position of a specific item. Records that are stored in a random access file must be the same size and all records must have the same length. This means that the size of a record cannot change. (Why?)

In Java, the sizes of the primitive data types are well documented and guaranteed to be the same on all systems. If an object’s fields are all of the primitive data types, you can easily calculate the size of the record: it will be the sum of the sizes of all the fields. You can handle the case of a character string by making sure that a String field is always written as the same number of characters. If the string is too long, cut it off; if too short, pad with blanks.

NOTE: Remember that when Java writes a String to a file, it also precedes it with a 2-byte length value and expects to find that value when reading a String. This means that your record length will be increased by 2 bytes for each string in the record.

Roster File – The purpose of this program is to accept information from the user and, using that info, create a file which contains information about fantasy game players. It will in essence be a database of football or basketball or baseball players. Each player’s data will make up a single record in the file. Each record will start with an integer ID, a name field (first and last), a team name, an integer skill level (0-99) and last, the date that the player was drafted. The operation of this program will be as follows:

a. Create a direct access file.

i. Ask the user for a file location and filename.

ii. Create the File object

iii. Open the file

iv. If the file does not already exist Initialize it to recognizable characters

b. Ask the user for a command.

c. Read the user command and proceed accordingly;

i.“new” – make a new record

ii. “old” – retrieve and display an existing record

iii. “end” – terminate the program.

d. If the command was “new”

i. Ask the user for a positive integer ID number between 1 and 20, read the ID

ii. Ask the user for the player’s name, read the name

iii. Ask the user for the player’s team name, read the team name

iv. Ask the user for the player’s skill level (integer between 0 & 99), read the skill level

v. Ask the user for today’s date, read the date

vi. Create a single string to contain all the data for one record. The field lengths will be as follows:

1. ID – 5 characters

2. Name – 26 characters

3. Team name – 26 characters

4. Skill level – 5 characters

5. Draft date – 9 characters (ex: 25Jun2014)

vii. Convert the ID and skill level to Strings (5 chars)

viii. Make sure that the name, team name and date fields are the correct length. If a field is too short, pad it with blanks; if it is too long, cut it off!

ix. Move all fields to the single String created in step vi. above. This will result in a String of length 71

x. Write the record into the file, at the record location indicated by the ID.

xi. Go back to step b.

e. If the command was “old”

i. Ask the user for an ID, read the ID

ii. Use the ID to index into the file and retrieve the record

iii. Display the record to the user, formatted for readability.

iv. Go back to step b.

f. If the command was “end”

i. Close the file

ii. End the program.

Don’t forget that the inventory records must all be the same length. Otherwise, the “old” command won’t be able to find the record that the user wants to see. This will make a string that is 71 characters long (5 + 26 + 26 + 5 + 9) and will be written as an inventory record of length 73 bytes. You will write 71 bytes but Java will add a 2-byte length in front of the string, which you must know about when you are retrieving an old record. When you first create the file, you will create room for 20 inventory records, of length 73 each. This space must be created when the file is opened and then as each record is created by the user, it will be placed into a space that is already laid out.

The ID number will be an indication of where in the file the specific inventory record is stored. Thus, if the user asks for the record with ID number 13, the program should go to the 13th record in the file. The ID number will of course, also be stored inside the record itself in order to make it simple to display it.

Since the user will be entering integer values (ID number and skill level) there is the chance that the user will go temporarily insane and enter something that is not an integer. (Ex: 3.24 or XYZ). Your program will throw an exception called NumberFormatException. Your code should catch this exception, notify the user of the error and try again to get a valid value. Thus there should be no reason for this program ever to crash.

You can get the values from the user by either reading from the console, using a Scanner object or by using the MessageDialog and the InputDialog.

Testing:

When testing this program, please try invalid values as follows:

a. non-integer for the ID

b. negative number for the ID

c. ID larger than 20

d. non-integer for the skill level

e. name shorter than 26 characters

f. name longer than 26 characters

g. team name shorter than 26 characters

h. team name longer than 26 characters

Testing should include:

a. Attempt to write valid records with IDs of 1, 5, 4, 2 in that order.

b. Attempt to retrieve each record after it is written

c. Attempt to retrieve all records in the order - IDs of 1, 5, 4, 2

d. Attempt to retrieve record 3.

e. Attempt to retrieve all records in the file & display to user.

f. Close the program, restart it and find the data file unchanged.

Demo program below! This demo writes only 10 records of only 16 characters each. Use it only as an aid to understanding the concepts that you will have to use in your program.

import java.io.*;

import javax.swing.JOptionPane;

public class Main

{

                                    // Number of records in the file.

final private static int MAX_RECORD_NUMBER = 10;

                                    // Size of record.

final private static int RECORD_LENGTH = 16;               

public static void main(String[] args)

                  throws FileNotFoundException, IOException

{          

File loc = new File("H:\01_IT219_Java02\week02\demo\demoDataFile.txt");

      RandomAccessFile store = new RandomAccessFile(loc, "rw");

      String Dummy = "abcdefghijklmnop";

      for (int i = 0; i < MAX_RECORD_NUMBER; ++i)

      {

            store.writeUTF(Dummy); // Fill file with dummy records.

      }

           

      String Description = "";

      int recLocation = 0;

      String where = "0";

      String cmd = "start";

      while (cmd.compareToIgnoreCase("end") != 0 )

      {

    cmd = JOptionPane.showInputDialog(null, "Please input a command:");

          if (cmd.compareToIgnoreCase("new") == 0)

          {

            // Command is "new" - user wants to make a new record

            Description = JOptionPane.showInputDialog

(null, "Please input a description: ");

            assert Description.length() == RECORD_LENGTH;

                       

            if (recLocation == 0)

            {

                  recLocation = 1;

            }

                                    // find the correct location in the file

            store.seek((RECORD_LENGTH+2) * (recLocation-1));     

            store.writeUTF(Description);

          }

          if (cmd.compareToIgnoreCase("old") == 0 )

          {

            // Command is "old" - user wants to see an existing record

            where = JOptionPane.showInputDialog(null, "Input rec number:”);

            recLocation = Integer.parseInt(where);

                       

            store.seek((RECORD_LENGTH+2) * (recLocation-1));

            Description = store.readUTF();

            JOptionPane.showMessageDialog(null, Description );

          }

      }

}

}

Explanation / Answer

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Scanner;

public class PlayersRandomFile {
   static int MAX_PLAYERS = 20;
   static int RECORD_SIZE = 73;
   static String BLANK_RECORD = String.format("%71s", " ");
   static Scanner keybd = new Scanner(System.in);
   static RandomAccessFile raf = null;
   private static RandomAccessFile openFile(String filepath) throws IOException
   {
       File f = new File(filepath);
       RandomAccessFile raf1 = null;
       boolean initialize = false;
      
       //if its not existing , we need to create and intialize 20 blank records
       if(!f.exists())
           initialize = true;
      
       raf1 = new RandomAccessFile(f, "rw");  
       if(initialize)
       {
           for(int i = 1; i <= MAX_PLAYERS; i++)
               raf1.writeUTF(BLANK_RECORD);
       }
          
       return raf1;
  
   }
  
   private static void menu() throws IOException
   {
       System.out.println("Please enter commands at the prompt. Commands are new, old and end");
       String command;
       boolean end = false;
       while(!end)
       {
           System.out.print(" > ");
           command = keybd.next().toLowerCase();
           switch(command)
           {
               case "new":
                   newRecord();
                   break;
               case "old":
                   oldRecord();
                   break;
               case "end":
                   end = true;
                   break;
               default: System.out.println("Command '" + command + "' not known!");
           }
       }
   }
  
   private static void newRecord() throws IOException
   {
       int id = -1, skill = -1;
       String playername, teamname, date;
       String input;
       while(true)
       {
           System.out.print(" Enter player ID (1-20): ");
           input = keybd.next();
           try
           {
               id = Integer.parseInt(input);
           }
           catch(NumberFormatException e)
           {
               id = 0;
           }
           if(id < 1 || id > 20)
               System.out.println("Invalid player ID!");
           else
               break;
       }
      
       System.out.print("Enter player name: ");
       while(true)
       {
           playername = keybd.nextLine().trim();
           if(!playername.equals(""))
               break;
       }
      
       System.out.print("Enter team name: ");
       while(true)
       {
           teamname = keybd.nextLine().trim();
           if(!teamname.equals(""))
               break;
       }
      
      
       while(true)
       {
           System.out.print("Enter player skill level (0-99): ");
           input = keybd.next();
           try
           {
               skill = Integer.parseInt(input);
           }
           catch(NumberFormatException e)
           {
               skill = -1;
           }
           if(skill < 0 || skill > 99)
               System.out.println("Invalid player skill level!");
           else
               break;
       }
      
       System.out.print("Enter today's date: ");
       date = keybd.next();
      
      
       //adjust sizes of field if longer
       if(playername.length() > 26)
           playername = playername.substring(0, 26);
      
       if(teamname.length() > 26)
           teamname = teamname.substring(0, 26);
      
       if(date.length() > 9)
           date = date.substring(0, 9);
      
       String record = String.format("%-5d%-26s%-26s%-5d%-9s",id, playername, teamname, skill, date);
      
       //calculate the correct record position in file and go to that offset and write the record
       int fileoffset = (id - 1) * RECORD_SIZE;
       raf.seek(fileoffset);
       raf.writeUTF(record);
       System.out.println("Record written successfully.");
   }
  
   private static void oldRecord() throws IOException
   {
       int id;
       String input;
       while(true)
       {
           System.out.print(" Enter player ID (1-20) of the record to fetch: ");
           input = keybd.next();
           try
           {
               id = Integer.parseInt(input);
           }
           catch(NumberFormatException e)
           {
               id = 0;
           }
           if(id < 1 || id > 20)
               System.out.println("Invalid player ID!");
           else
               break;
       }
      
       long fileoffset = (id - 1) * RECORD_SIZE;
       raf.seek(fileoffset);
       String record = raf.readUTF();
       if(record.trim().equals(""))
           System.out.println("Record for player ID " + id + " is blank.");
       else
           System.out.println("Fetched record: " + record);
   }
   public static void main(String[] args) {
      
              
       String filepath;
       keybd = new Scanner(System.in);
       System.out.print("Enter path/filename of file: ");
       filepath = keybd.nextLine().trim();
       try {
           raf = openFile(filepath);
           menu();
           raf.close();
          
       } catch (IOException e) {
           System.out.println(e.getMessage());
       }
      
   }
}

output

Enter path/filename of file: players.txt
Please enter commands at the prompt. Commands are new, old and end

> old

Enter player ID (1-20) of the record to fetch: 4
Record for player ID 4 is blank.

> new

Enter player ID (1-20): 1
Enter player name: John Smith
Enter team name: Team A

Enter player skill level (0-99): -1
Invalid player skill level!

Enter player skill level (0-99): 191
Invalid player skill level!

Enter player skill level (0-99): 89
Enter today's date: 22Jul2017
Record written successfully.

> new

Enter player ID (1-20): 56
Invalid player ID!

Enter player ID (1-20): 5
Enter player name: Jonathan B Peter Henry Long name1233
Enter team name: Team B

Enter player skill level (0-99): 67
Enter today's date: 22Jul2017
Record written successfully.

> old

Enter player ID (1-20) of the record to fetch: 1
Fetched record: 1 John Smith Team A 89 22Jul2017

> old

Enter player ID (1-20) of the record to fetch: 5
Fetched record: 5 Jonathan B Peter Henry LonTeam B 67 22Jul2017

> new

Enter player ID (1-20): 4
Enter player name: Michael Shaun
Enter team name: Team A

Enter player skill level (0-99): 99
Enter today's date: 22Jul2017
Record written successfully.

> new

Enter player ID (1-20): 2
Enter player name: Bob Smith
Enter team name: Team B

Enter player skill level (0-99): 70
Enter today's date: 22Jul2017
Record written successfully.

> old

Enter player ID (1-20) of the record to fetch: 1
Fetched record: 1 John Smith Team A 89 22Jul2017

> old

Enter player ID (1-20) of the record to fetch: 2
Fetched record: 2 Bob Smith Team B 70 22Jul2017

> old

Enter player ID (1-20) of the record to fetch: 4
Fetched record: 4 Michael Shaun Team A 99 22Jul2017

> old

Enter player ID (1-20) of the record to fetch: 5
Fetched record: 5 Jonathan B Peter Henry LonTeam B 67 22Jul2017

> old

Enter player ID (1-20) of the record to fetch: 3
Record for player ID 3 is blank.

> end