FLIGHT RESERVATION SYSTEM (1st Semester Java Project)
Console-Based Airline
Reservation System
A complete breakdown of how this Java project works: the data structures, boot sequence, file persistence, and the logic inside every feature method.
First semester project: Programming Fundamentals (documentation written later)
What the program does
A fully console-based reservation system with no database. Everything is persisted through plain text CSV files inside a Data/ folder, so data survives restarts. The program boots by loading that data into memory, then enters a menu loop.
Data/. No external libraries or database.Project skeleton and state
All in-memory state lives at the class level as static arrays. The seat map is a 3D array indexed as seats[flightIndex][row][col]. Rows map to A through E, columns map to 1 through 4.
static final int MAX_FLIGHTS = 100; static final int ROWS = 5; // A to E static final int COLS = 4; // 1 to 4 static String[] flightIDs = new String[MAX_FLIGHTS]; static String[] sources = new String[MAX_FLIGHTS]; static String[] dests = new String[MAX_FLIGHTS]; static double[] prices = new double[MAX_FLIGHTS]; // seats[flightIndex][row][col] holds 'O' (open) or 'X' (booked) static char[][][] seats = new char[MAX_FLIGHTS][ROWS][COLS]; static int flightCount = 0; static Scanner scanner = new Scanner(System.in); // Platform-independent paths static final String DATA_DIR = "Data" + File.separator; static final String FLIGHTS_FILE = DATA_DIR + "flights.txt"; static final String BOOKINGS_FILE = DATA_DIR + "bookings.txt";
i represents one flight across all arrays simultaneously. The 3D char array for seats is the most interesting part: seats[i][row][col] gives direct access to any seat on any flight in O(1).
The boot sequence
Three calls in main(). That is the entire startup.
public static void main(String[] args) { loadFlights(); // read Data/flights.txt into arrays loadBookings(); // read Data/bookings.txt and mark seats X mainMenu(); // enter the menu loop }
Flights loaded successfully.
Bookings replayed onto seat map.
=============================
| FLIGHT RESERVATION SYSTEM |
=============================
1. View all flights
2. Book ticket
3. Cancel ticket
4. Admin login
5. Exit
Enter your choice: _
Loading flights
Reads Data/flights.txt line by line. Each line is CSV: FLIGHT_ID,SOURCE,DEST,PRICE. After parsing, every seat for that flight is initialized to 'O'.
PK101,ISB,LHE,7500
PK102,ISB,KHI,12000
PK103,LHE,KHI,9500
Scanner fileScanner = new Scanner(file); while (fileScanner.hasNextLine() && flightCount < MAX_FLIGHTS) { String line = fileScanner.nextLine().trim(); if (line.isEmpty()) continue; String[] parts = line.split(","); if (parts.length < 4) continue; // skip malformed lines flightIDs[flightCount] = parts[0]; sources[flightCount] = parts[1]; dests[flightCount] = parts[2]; prices[flightCount] = Double.parseDouble(parts[3]); for (int i = 0; i < ROWS; i++) for (int j = 0; j < COLS; j++) seats[flightCount][i][j] = 'O'; // all open flightCount++; }
If the file does not exist, the program prints a message and continues. It does not crash. The Data/ directory is created via mkdirs() if missing.
Loading bookings
After all flights are in memory with all seats open, this method replays past bookings by marking the correct seats as 'X'.
PK101,Ali,A1
PK101,Arham,B2
PK102,Sara,C3
String seat = parts[2]; int row = seat.charAt(0) - 'A'; // 'A'=0, 'B'=1, ... int col = Integer.parseInt(seat.substring(1)) - 1; // "1"=0, "2"=1, ... if (row >= 0 && row < ROWS && col >= 0 && col < COLS) { seats[index][row][col] = 'X'; }
The char subtraction trick is clean: 'A' - 'A' = 0, 'B' - 'A' = 1, and so on. Same idea for the column number. After this method runs, the seat map perfectly reflects the last saved state.
Displaying flights
Counts open seats live by scanning the seat array for each flight, then prints a formatted table using printf.
System.out.printf("%-10s %-10s %-10s %-10s %-10s%n", "ID", "From", "To", "Price", "Seats Left"); for (int i = 0; i < flightCount; i++) { int freeCount = 0; for (int r = 0; r < ROWS; r++) for (int c = 0; c < COLS; c++) if (seats[i][r][c] == 'O') freeCount++; System.out.printf("%-10s %-10s %-10s %-10.1f %-10d%n", flightIDs[i], sources[i], dests[i], prices[i], freeCount); }
| ID | From | To | Price (PKR) | Seats Left |
|---|---|---|---|---|
| PK101 | ISB | LHE | 7,500 | 18 |
| PK102 | ISB | KHI | 12,000 | 20 |
| PK103 | LHE | KHI | 9,500 | 19 |
Booking a ticket
The most interactive method. It runs through five steps in sequence.
Step 1 and 2: Pick flight, view seat map
After the user enters a flight ID, the program prints a visual grid of the current seat status before asking which seat they want.
Step 3: Validate the seat code
int row = seat.charAt(0) - 'A'; int col; try { col = Integer.parseInt(seat.substring(1)) - 1; } catch (NumberFormatException e) { System.out.println("Invalid seat number."); return; } if (row < 0 || row >= ROWS || col < 0 || col >= COLS) { System.out.println("Seat out of range."); return; } if (seats[index][row][col] == 'X') { System.out.println("Seat already booked."); return; }
Step 4 and 5: Save and generate ticket
seats[index][row][col] = 'X'; // mark in memory // append to bookings.txt FileWriter writer = new FileWriter(BOOKINGS_FILE, true); writer.write(flightID + "," + name + "," + seat + "\n"); writer.close(); // generate ticket file PrintWriter ticket = new PrintWriter(ticketFileName); ticket.println("||| FLIGHT TICKET DETAILS |||"); ticket.println("Name: " + name); ticket.println("Flight ID: " + flightID); ticket.println("From: " + sources[index]); ticket.println("To: " + dests[index]); ticket.println("Seat: " + seat); ticket.println("Price: " + prices[index]); ticket.close();
loadBookings() will read that line and mark the seat X again. State is fully recovered.
Cancelling a booking
Two things must happen: free the seat in memory, and remove the exact line from bookings.txt without touching the rest of the file.
Free the seat
if (seats[index][row][col] == 'O') { System.out.println("This seat is not currently booked."); return; } seats[index][row][col] = 'O';
Temp-file swap to remove the record
You cannot delete a line from the middle of a text file in place. The standard solution is to write a new temp file with every line except the one you want gone, then replace the original.
File file = new File(BOOKINGS_FILE); File tempFile = new File(DATA_DIR + "temp_bookings.txt"); BufferedReader reader = new BufferedReader(new FileReader(file)); PrintWriter writer = new PrintWriter(new FileWriter(tempFile)); String line; while ((line = reader.readLine()) != null) { if (line.trim().isEmpty()) continue; String[] parts = line.split(","); if (parts[0].equals(flightID) && parts[2].equals(seat)) continue; // skip this one line writer.println(line); } reader.close(); writer.close(); if (file.delete()) tempFile.renameTo(file);
Admin panel
Password-protected entry. For a demo project this is fine. In production you would never hardcode credentials in source code.
System.out.print("Enter admin password: "); String pwd = scanner.nextLine(); if (!pwd.equals("admin123")) { System.out.println("Incorrect password."); return; }
Admin Menu
1. Add flight
2. Remove flight
3. Back to main menu
Enter choice: 1
Enter new Flight ID: PK104
Enter source: KHI
Enter destination: LHE
Enter price: 8500
Flight added.
Adding a flight
Validates inputs, checks for duplicate IDs, initializes the seat map, appends to flights.txt, then increments flightCount.
// duplicate check for (int i = 0; i < flightCount; i++) if (flightIDs[i].equals(flightID)) { System.out.println("Flight ID already exists."); return; } // init seat map for (int i = 0; i < ROWS; i++) for (int j = 0; j < COLS; j++) seats[flightCount][i][j] = 'O'; // persist PrintWriter writer = new PrintWriter(new FileWriter(FLIGHTS_FILE, true)); writer.println(flightID + "," + src + "," + dst + "," + price); writer.close(); flightCount++;
Removing a flight
Three places to clean up: in-memory arrays, flights.txt, and all related records in bookings.txt.
for (int i = index; i < flightCount - 1; i++) { flightIDs[i] = flightIDs[i + 1]; sources[i] = sources[i + 1]; dests[i] = dests[i + 1]; prices[i] = prices[i + 1]; seats[i] = seats[i + 1]; } flightCount--;
Then both files are rewritten using the same temp-file swap pattern from cancellation: skip lines that belong to the removed flight, write everything else, swap.
Validation and edge cases
parts.length before accessing any index. Malformed rows are skipped silently.File formats
PK101,ISB,LHE,7500
PK102,ISB,KHI,12000
PK101,Ali,A1
PK102,Sara,B3
Full execution map
What this teaches
File.separator means paths work on Windows, Linux, and Mac without changes.If you are just starting out
Pick a small but realistic problem. Keep the data model simple. Wire persistence early so you can see your data survive a restart. That is the moment the project starts feeling like a real system instead of a homework exercise.
If you want the same structure: copy the method layout and evolve it feature by feature. loadFlights, loadBookings, displayFlights, bookTicket, cancelTicket, adminMenu, addFlight, removeFlight. One method at a time.