承 84 — BufferedReader
到本頁最下面的 本篇代碼
下載 directions_big.txt、locations_big.txt
並把代碼裡的文檔路徑更新成這兩個
來比對當數據龐大的時候,我們從文檔寫跟讀和當初寫在代碼裡的差異
輸出結果:
YOU ARE STANDING AT THE END OF A ROAD BEFORE A SMALL BRICK BUILDING. AROUND YOU IS A FOREST. A SMALL STREAM FLOWS OUT OF THE BUILDING AND DOWN A GULLY.
Available exits are Q, S, D, U, E, W, N,
s
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A ROCKY BED.
Available exits are Q, S, D, E, U, W, N,
e
YOU ARE IN OPEN FOREST, WITH A DEEP VALLEY TO ONE SIDE.
Available exits are Q, S, D, E, W, N,
d
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A ROCKY BED.
Available exits are Q, S, D, E, U, W, N,
e
YOU ARE IN OPEN FOREST, WITH A DEEP VALLEY TO ONE SIDE.
Available exits are Q, S, D, E, W, N,
w
YOU ARE IN OPEN FOREST, WITH A DEEP VALLEY TO ONE SIDE.
Available exits are Q, S, D, E, W, N,
n
YOU ARE IN OPEN FOREST NEAR BOTH A VALLEY AND A ROAD.
Available exits are Q, S, D, E, W, N,
e
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A ROCKY BED.
Available exits are Q, S, D, E, U, W, N,
u
YOU ARE IN OPEN FOREST, WITH A DEEP VALLEY TO ONE SIDE.
Available exits are Q, S, D, E, W, N,
q
YOU ARE SITTING IN FRONT OF A COMPUTER LEARNING JAVA.
Tim 說這是當初 colossal cave adventure game 的資料
而為什麼敘述都是大寫的呢?
因為在當時 1970 年代的 terminal 只能輸出大寫
真是一款上古遊戲呢!
當時的電腦玩家用 terminal 玩遊戲,還真強 = =
小挑戰:
將 static
裡的兩個讀檔文件改成 try-with-resources
補充: Java try-with-resources examples
參考答案:
// read locations.txt with try-with-resources
try (Scanner scanner = new Scanner(new FileReader("src/introduceIo/locations_big.txt"))) {
scanner.useDelimiter(",");
while (scanner.hasNext()) {
int locInt = scanner.nextInt();
scanner.skip(scanner.delimiter());
String description = scanner.nextLine();
Map<String, Integer> tempExit = new HashMap<>();
locations.put(locInt, new Location(locInt, description, tempExit));
}
} catch (IOException e) {
e.printStackTrace();
}// read directions.txt with try-with-resources
try (Scanner scanner = new Scanner(new BufferedReader(new FileReader("src/introduceIo/directions_big.txt")))) {
while (scanner.hasNextLine()) {
String input = scanner.nextLine();
String[] data = input.split(",");
int loc = Integer.parseInt(data[0]);
String direction = data[1];
int destination = Integer.parseInt(data[2]);
Location location = locations.get(loc);
location.addExit(direction, destination);
}
} catch (IOException e) {
e.printStackTrace();
}
還能這樣寫
// read directions.txt with try-with-resources version 2 try (BufferedReader dirFile = new BufferedReader(new FileReader("src/introduceIo/directions_big.txt"))) {
String input;
while ((input = dirFile.readLine())!=null) {
String[] data = input.split(","); int loc = Integer.parseInt(data[0]);
String direction = data[1];
int destination = Integer.parseInt(data[2]); Location location = locations.get(loc);
location.addExit(direction, destination);
}
} catch (IOException e) {
e.printStackTrace();
}
不過比較起來,感覺還是 Scanner
比較簡單好用
小挑戰:
1.將剩下的讀取跟寫入都改成 BufferedReader
2.修改寫入,不要把出口 Q 也寫進去,讓寫入的結果跟原來的 directions_big.txt 內容一樣
ps.可把 Locations、Location 的 Hashmap
改成 LinkedHashMap
也可不改
參考答案:
Location.java
public Location(int locationID, String description, Map<String, Integer> exits) {
this.locationID = locationID;
this.description = description;
if (exits != null) {
this.exits = new LinkedHashMap<String, Integer>(exits);
} else {
this.exits = new LinkedHashMap<String, Integer>();
}
}
Locations.java
private static Map<Integer, Location> locations = new LinkedHashMap<Integer, Location>();
public static void main(String[] args) throws IOException { try (BufferedWriter file = new BufferedWriter(new FileWriter("src/introduceIo/locations_big.txt"));
BufferedWriter dirFile = new BufferedWriter(new FileWriter("src/introduceIo/directions_big.txt"))) {
for (Location location : locations.values()) {
file.write(location.getLocationID() + "," + location.getDescription() + "\n");
for (String direction : location.getExits().keySet()) {
dirFile.write(location.getLocationID() + "," + direction + "," + location.getExits().get(direction) + "\n");
}
}
}
}
static { try (Scanner scanner = new Scanner(new BufferedReader(new FileReader("src/introduceIo/locations_big.txt")))) {
scanner.useDelimiter(",");
while (scanner.hasNext()) {
int locInt = scanner.nextInt();
scanner.skip(scanner.delimiter());
String description = scanner.nextLine();
Map<String, Integer> tempExit = new HashMap<>();
locations.put(locInt, new Location(locInt, description, tempExit));
}
} catch (IOException e) {
e.printStackTrace();
}
}
Main.java
package introduceIo;import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;public class Main {
private static Locations locations = new Locations(); public static void main(String[] args) {
// Change the program to allow players to type full words, or phrases, then move to the
// correct location based upon their input.
// The player should be able to type commands such as "Go West", "run South", or just "East"
// and the program will move to the appropriate location if there is one. As at present, an
// attempt to move in an invalid direction should print a message and remain in the same place.
//
// Single letter commands (N, W, S, E, Q) should still be available. Scanner scanner = new Scanner(System.in); Map<String, String> vocabulary = new HashMap<String, String>();
vocabulary.put("QUIT", "Q");
vocabulary.put("NORTH", "N");
vocabulary.put("SOUTH", "S");
vocabulary.put("WEST", "W");
vocabulary.put("EAST", "E"); int loc = 1;
while (true) {
System.out.println(locations.get(loc).getDescription()); if (loc == 0) {
break;
} Map<String, Integer> exits = new LinkedHashMap<String, Integer>();
exits.put("Q", 0);
exits.putAll(locations.get(loc).getExits()); System.out.print("Available exits are ");
for (String exit : exits.keySet()) {
System.out.print(exit + ", ");
}
System.out.println(); String direction = scanner.nextLine().toUpperCase();
if (direction.length() > 1) {
String[] words = direction.split(" ");
for (String word : words) {
if (vocabulary.containsKey(word)) {
direction = vocabulary.get(word);
break;
}
}
} if (exits.containsKey(direction)) {
loc = exits.get(direction); } else {
System.out.println("You cannot go in that direction");
}
} }
}