I/O--(下)非流結構&記憶體流&讀檔&登入校驗
操作流
流檔案實現的登入註冊校驗
DAO-介面操作集
POJO-簡單使用者定義集
DAO.impl-介面操作實現
- Code總體邏輯:
-
定義操作介面:註冊-登入。
-
定義具體實現介面:註冊-登入。 操作類介面保證檔案的存在性,必須將建立檔案作為靜態程式碼塊實現。 註冊將user物件的Name=PassWord通過開啟user.txt檔案物件流寫入到user.txt,考慮寫入可能失敗所以需要使用try…catch…finally去實現,返回boolean型。 登入類,通過開啟檔案物件流,讀取每一行資料,並且通過split函式獲取賬號=密碼,與通過介面輸入的值通過equals匹配,若成功,返回true。
-
物件類:定義簡單的使用者物件,以及對應的成員變數和成員方法。
-
主函式類:介面控制問題:獲取選項;判斷合理性;呼叫對應的函式即可。
-
eg:
/*for example*/ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Scanner; /*使用者定義*/ class User { private String username; private String password; public User() { } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } /*操作介面定義*/ interface UserDao { public abstract boolean isLogin(String username, String password); public abstract void regist(User user); } /*介面具體實現*/ class UserDaoImpl implements UserDao { //保證儲存檔案的存在. private static File file = new File("user.txt"); static { try { file.createNewFile(); } catch (IOException e) { System.out.println("建立檔案失敗."); // e.printStackTrace(); } } @Override public boolean isLogin(String username, String password) { boolean flag = false; BufferedReader br = null; try { br = new BufferedReader(new FileReader(file)); String line = null; while ((line = br.readLine()) != null) { String[] datas = line.split("="); if (datas[0].equals(username) && datas[1].equals(password)) { flag = true; break; } } } catch (FileNotFoundException e) { System.out.println("使用者登入找不到資訊所在的檔案."); // e.printStackTrace(); } catch (IOException e) { System.out.println("使用者登入失敗."); // e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { System.out.println("使用者登入釋放資源失敗."); // e.printStackTrace(); } } } return flag; } @Override public void regist(User user) { /* * 資料的儲存規則為:使用者名稱=密碼. */ BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(file, true)); bw.write(user.getUsername() + "=" + user.getPassword()); bw.newLine(); bw.flush(); } catch (IOException e) { System.out.println("使用者註冊失敗."); // e.printStackTrace(); } finally { if (bw != null) { try { bw.close(); } catch (IOException e) { System.out.println("使用者註冊釋放資源失敗."); // e.printStackTrace(); } } } } } /*Game主函式*/ class GuessNumber { private GuessNumber() { } public static void start() { int number = (int) (Math.random() * 100) + 1; int count = 0; while (true) { Scanner sc = new Scanner(System.in); System.out.println("請輸入資料(1-100):"); int guessNumber = sc.nextInt(); count++; // 判斷 if (guessNumber > number) { System.out.println("你猜的資料" + guessNumber + "大了."); } else if (guessNumber < number) { System.out.println("你猜的資料" + guessNumber + "小了."); } else { System.out.println("恭喜你," + count + "次就猜中了!"); break; } } } } /*主函式部分*/ public class InterCalc { public static void main(String[] args) { // 為了能夠回來 while (true) { // 歡迎介面,給出選擇項 System.out.println("--------------歡迎光臨--------------"); System.out.println("1 登入"); System.out.println("2 註冊"); System.out.println("3 退出"); System.out.println("請輸入你的選擇:"); Scanner sc = new Scanner(System.in); String choiceString = sc.nextLine(); // 多型,介面內部呼叫User。 UserDao ud = new UserDaoImpl(); switch (choiceString) { case "1": // 登入介面,請輸入使用者名稱和密碼 System.out.println("--------------登入介面--------------"); System.out.println("請輸入使用者名稱:"); String username = sc.nextLine(); System.out.println("請輸入密碼:"); String password = sc.nextLine(); boolean flag = ud.isLogin(username, password); if (flag) { System.out.println("登入成功。"); System.out.println("你玩嗎?y/n"); while (true) { String resultString = sc.nextLine(); if (resultString.equalsIgnoreCase("y")) { // 玩遊戲 GuessNumber.start(); System.out.println("你還玩嗎?y/n"); } else { break; } } System.out.println("謝謝使用,歡迎下次再來!"); System.exit(0); // break; //這裡寫break,結束的是switch } else { System.out.println("使用者名稱或者密碼有誤,登入失敗!"); } break; case "2": // 歡迎介面,請輸入使用者名稱和密碼 System.out.println("--------------註冊介面--------------"); System.out.println("請輸入使用者名稱:"); String newUsername = sc.nextLine(); System.out.println("請輸入密碼:"); String newPassword = sc.nextLine(); User user = new User(); user.setUsername(newUsername); user.setPassword(newPassword); ud.regist(user); System.out.println("註冊成功."); break; case "3": System.out.println("歡迎下次再來!"); System.exit(0); break; default: System.out.println("請重新選擇正確的選項!"); break; } } } }
-
帶本地檔案驗證次數的登入註冊驗證—轉到文章最後。
-
資料操作流 - 操作基本型別資料的流
-
DataOutputStream(OutputStream out)
建立一個新的資料輸出流,以將資料寫入指定的底層輸出流。
-
DataInputStream
-
DataOutputStream
-
codeDemo:
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* * 資料輸入流:DataInputStream * DataInputStream(InputStream in). * 資料輸出流:DataOutputStream * DataOutputStream(OutputStream out). */ public class DataStream{ public static void main(String[] args) throws IOException { write(); read(); } private static void read() throws IOException { // DataInputStream(InputStream in) DataInputStream dis = new DataInputStream( new FileInputStream("dos.txt")); // 讀資料 byte b = dis.readByte(); short s = dis.readShort(); int i = dis.readInt(); long l = dis.readLong(); float f = dis.readFloat(); double d = dis.readDouble(); char c = dis.readChar(); boolean bb = dis.readBoolean(); dis.close(); System.out.println(b); System.out.println(s); System.out.println(i); System.out.println(l); System.out.println(f); System.out.println(d); System.out.println(c); System.out.println(bb); } private static void write() throws IOException { // DataOutputStream(OutputStream out) // 建立資料輸出流物件 DataOutputStream dos = new DataOutputStream(new FileOutputStream( "dos.txt")); // 寫資料 dos.writeByte(10); dos.writeShort(100); dos.writeInt(1000); dos.writeLong(10000); dos.writeFloat(12.34F); dos.writeDouble(12.56); dos.writeChar('a'); dos.writeBoolean(true); dos.close(); } }
-
記憶體操作流
描述:有些時候我們操作完畢後,未必需要產生一個檔案,就可以使用記憶體操作流。
- ByteArrayInputStream,ByteArrayOutputStream.
- CharArrayReader,CharArrayWriter.
- StringReader,StringWriter.
/*for example*/ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; /* * 記憶體操作流:用於處理臨時儲存資訊的,程式結束,資料就從記憶體中消失,且資料的操作不需要關閉流物件。 * 位元組陣列: * ByteArrayInputStream * ByteArrayOutputStream * 字元陣列: * CharArrayReader * CharArrayWriter * 字串: * StringReader * StringWriter */ public class ByteArrayStream{ public static void main(String[] args) throws IOException { // 寫資料 // ByteArrayOutputStream() ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 寫資料 for (int x = 0; x < 10; x++) { baos.write(("hello" + x).getBytes()); } // 釋放資源 // 通過檢視原始碼我們知道這裡什麼都沒做,所以根本不需要close(). // baos.close(); // public byte[] toByteArray() byte[] bys = baos.toByteArray(); // 讀資料 // ByteArrayInputStream(byte[] buf) ByteArrayInputStream bais = new ByteArrayInputStream(bys); int by = 0; while ((by = bais.read()) != -1) { System.out.print((char) by); } // bais.close(); } }
列印流
- 描述:包括位元組列印流,字元列印流。
- 特點:
只操作目的地,不操作資料來源,也就是說只有寫函式沒有讀取函式。
可以操作任意型別的資料。
如果啟用了自動重新整理,在呼叫println()方法的時候,能夠換行並重新整理。
可以直接操作檔案.
-
直接操作檔案
/*for example*/ /*複製文字檔案*/ BufferedReader br = new BufferedReader(new FileReader("a.txt")); /*啟動自動重新整理:包括寫入,寫入新行,重新整理等操作。*/ PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true); String line = null; while((line=br.readLine())!=null) { pw.println(line); } pw.close(); br.close();
標準輸入輸出流
-
System類中的兩個成員變數:
public static final InputStream in “標準”輸入流。 public static final PrintStream out “標準”輸出流。
-
三種鍵盤錄入方式
-
輸出語句的原理和如何使用字元流輸出資料.
System.out.println("helloworld"); //reg. PrintStream ps = System.out; //reg1. ps.println("helloworld"); //reg2. /*System.out用字元緩衝流包裝使用.*/ BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); bw.write("hello"); bw.newLine(); bw.write("world"); bw.newLine(); bw.write("java"); bw.newLine(); bw.flush(); bw.close();
隨機訪問流
RandomAccessFile類不屬於流,是Object類的子類。
它融合了InputStream和OutputStream的功能。
支援對檔案的隨機訪問讀取和寫入。
public RandomAccessFile(String name,String mode):
第一個引數是檔案路徑,第二個引數是操作檔案的模式。
模式有四種,我們最常用的一種叫"rw",這種方式表示我既可以寫資料,也可以讀取資料。
mode:must be one of "r", "rw", "rws", or "rwd"
/*for example*/
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
write();
read();
}
private static void read() throws IOException {
RandomAccessFile raf = new RandomAccessFile("raf.txt", "r");
int i = raf.readInt();
System.out.print(i);
System.out.println("\t當前指標位置:" + raf.getFilePointer());
char ch = raf.readChar();
System.out.print(ch);
System.out.println("\t當前指標位置:" + raf.getFilePointer());
String s = raf.readUTF();
System.out.print(s);
System.out.println("\t當前指標位置:" + raf.getFilePointer());
String ss = raf.readUTF();
System.out.print(ss);
System.out.println("\t當前指標位置:" + raf.getFilePointer());
String sss = raf.readUTF();
System.out.print(sss);
System.out.println("\t當前指標位置:" + raf.getFilePointer());
System.out.println("------this is a dividing line------");
raf.seek(4);
ch = raf.readChar();
System.out.println(ch);
}
private static void write() throws IOException {
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
raf.writeInt(100);
raf.writeChar('a');
raf.writeUTF("中華");
raf.writeUTF("人民");
raf.writeUTF("共和國");
raf.close();
}
}
result:
100 當前指標位置:4
a 當前指標位置:6
中華 當前指標位置:14
人民 當前指標位置:22
共和國 當前指標位置:33
------this is a dividing line------
a
/* 為什麼a指標4,中華為14,因為多讀兩個,後面的幾個string就是驗證這個表現的.*/
合併流
-
簡單的描述就是將把多個輸入流的資料寫到一個輸出流中,可以作為檔案的複製合併操作。
-
構造方法:
SequenceInputStream(InputStream s1, InputStream s2) . SequenceInputStream(Enumeration<? extends InputStream> e).
-
檔案合併
/*for example:兩種方式實現的檔案合併.*/
/* 要求:a.txt+b.txt=c.txt */ import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; public class SequenceInputStreamDemo { public static void main(String[] args) throws IOException { /*SequenceInputStream(InputStream s1, InputStream s2)*/ InputStream s1 = new FileInputStream("a.txt"); InputStream s2 = new FileInputStream("b.txt"); SequenceInputStream sis = new SequenceInputStream(s1, s2); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("c.txt")); byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); sis.close(); } }
/* 要求:a.txt+b.txt+c.txt=final.txt,如下: */ import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.util.Enumeration; import java.util.Vector; public class SequenceInputStreamDemo2 { public static void main(String[] args) throws IOException { // ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java // SequenceInputStream(Enumeration e) // Enumeration<E> elements() Vector<InputStream> v = new Vector<InputStream>(); InputStream s1 = new FileInputStream("a.txt"); InputStream s2 = new FileInputStream("b.txt"); InputStream s3 = new FileInputStream("c.txt"); v.add(s1); v.add(s2); v.add(s3); Enumeration<InputStream> en = v.elements(); SequenceInputStream sis = new SequenceInputStream(en); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("final.txt")); byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); sis.close(); } }
序列化流
描述:可以把物件寫入文字檔案或者在網路中傳輸。
-
序列化&反序列化
- 序列化流:把物件按照流一樣的方式存入文字檔案或者在網路中傳輸。物件 – 流資料(ObjectOutputStream)。
- 反序列化流:把文字檔案中的流物件資料或者網路中的流物件資料還原成物件。流資料 – 物件ObjectInputStream)。 使用方法:
讓要被序列化的物件所屬類實現序列化介面-> 介面為:Serializable->由於一般是讀取之前儲存的資料物件,而不是儲存&讀取,所以一旦對原物件進行修改後,將報錯:serialVersionUID的匹配性問題-> 解決辦法:使用第一個選項使用預設or第二個使用動態serialVersionUID-> 可能對某些物件的成員變數不需要寫入,可以使用transient來修飾。 Serializable-----該介面是一個標記介面。沒有功能需要實現。
/*for example*/ /*POJO--簡單物件類*/ import java.io.Serializable; public class Person implements Serializable { //序列化介面,無內容的標記介面,目的是對IO格式的匹配。 private String name; private transient int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } } /*主函式類*/ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ObjectStream{ public static void main(String[] args) throws IOException, ClassNotFoundException { write(); read(); } /*反序列化:流->還原物件.*/ private static void read() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "oos.txt")); Object obj = ois.readObject(); ois.close(); System.out.println(obj); } /*序列化:物件-流.*/ private static void write() throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( "oos.txt")); Person p = new Person("Tom", 3 ); oos.writeObject(p); oos.close(); } }
Properties
描述:Properties類表示一組持久的屬性。 Properties可以儲存到流中或從流中載入。 屬性列表中的每個鍵及其對應的值都是一個字串。 屬性列表可以包含另一個屬性列表作為其“預設值”; 如果在原始屬性列表中找不到屬性鍵,則會搜尋此第二個屬性列表。
因為Properties從繼承Hashtable時, put種putAll方法可應用於Properties物件。 強烈不鼓勵使用它們,因為它們允許呼叫者插入其鍵或值不是Strings 。 應該使用setProperty方法。 如果store或save方法在包含非String鍵或值的“受損害” Properties物件上呼叫,則呼叫將失敗。 類似地,如果在包含非String金鑰的“受損害” Properties物件上呼叫propertyNames或list方法的呼叫將失敗。
簡而言之:就是一組持久的屬性Hashtable子類,鍵值對都是String的數集。
繼承結構如下:
-
特有or常用函式
import java.util.Properties; import java.util.Set; /* * Properties:屬性集合類,是一個可以和IO流相結合使用的集合類。 * Properties 可儲存在流中或從流中載入,屬性列表中每個鍵及其對應值都是一個字串。 * * 是Hashtable的子類=>是一個Map集合。 */ public class PropertiesDemo { public static void main(String[] args) { //錯誤用法:Properties<String, String> prop = new Properties<String, String>(); Properties prop = new Properties(); prop.put("001", "hello"); prop.put("002", "world"); prop.put("003", "java"); Set<Object> set = prop.keySet(); for (Object key : set) { Object value = prop.get(key); System.out.println(key + "---" + value); } } }
/* public Object setProperty(String key,String value) //新增元素鍵值對組。 public String getProperty(String key) //由鍵獲取值。 public Set<String> stringPropertyNames() //獲取鍵集合,屬性指定為String。 */ import java.util.Properties; import java.util.Set; public class PropertiesCc { public static void main(String[] args) { Properties prop = new Properties(); prop.setProperty("Jack", "5"); prop.setProperty("Tom", "2"); prop.setProperty("coffee", "3"); /*public Set<String> stringPropertyNames():獲取所有的鍵的集合*/ Set<String> set = prop.stringPropertyNames(); for (String key : set) { String value = prop.getProperty(key); System.out.println(key + "---" + value); } } }
-
Properties&IO流
-
把集合中的資料儲存到文字檔案中
public void store(Writer writer,String comments). public void store(OutputStream out,String comments).
-
把鍵值對形式的文字檔案內容載入到集合中
public void load(Reader reader). public void load(InputStream inStream).
-
Code-eg:
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Properties; public class PropertiesCc{ public static void main(String[] args) throws IOException { myLoad(); myStore(); } private static void myStore() throws IOException { Properties prop = new Properties(); prop.setProperty("Jack", "5"); prop.setProperty("Tom", "2"); prop.setProperty("coffee", "3"); /*public void store(Writer writer,String comments):把集合中的資料儲存到檔案。*/ Writer w = new FileWriter("Store.txt"); prop.store(w, "Tips:"); w.close(); } private static void myLoad() throws IOException { Properties prop = new Properties(); /*public void load(Reader reader):把檔案中的資料讀取到集合中,這個檔案的資料必須是鍵值對形式。*/ Reader r = new FileReader("load.txt"); prop.load(r); r.close(); System.out.println("prop:" + prop); } }
-
Properties&讀檔
/*for example*/ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Properties; public class PropertiesDd { public static void main(String[] args) throws IOException { File file = new File("count.txt"); if (!file.exists()) { file.createNewFile(); Properties prop = new Properties(); prop.setProperty("count", "0"); Writer w = new FileWriter("count.txt"); prop.store(w, null); w.close(); } /*把資料載入到集合*/ Properties prop = new Properties(); Reader r = new FileReader("count.txt"); prop.load(r); r.close(); /*已知鍵值對關係*/ String value = prop.getProperty("count"); int number = Integer.parseInt(value); if (number > 3) { System.out.println("試玩結束,請付費!"); System.exit(0); } else { number++; prop.setProperty("count", String.valueOf(number)); Writer w = new FileWriter("count.txt"); prop.store(w, null); w.close(); GuessNumber.start(); } } }
-
NIO
- JDK4出現的NIO,對以前的IO操作進行了優化,但是目前還是使用以前的IO流操作…
- JDK7的NIO
-
Path:路徑
-
Paths:通過靜態方法返回一個路徑。
-
Files:常用函式如下使用。
-
code–eg:
import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; /* * Paths:靜態方法返回一個路徑. * public static Path get(URI uri). * Files:靜態方法. * public static long copy(Path source,OutputStream out):複製檔案 * public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options) */ public class NIOAa { public static void main(String[] args) throws IOException { /* public static long copy(Path source,OutputStream out)--複製檔案 */ Files.copy(Paths.get("Source.java"), new FileOutputStream("Copy.java")); ArrayList<String> array = new ArrayList<String>(); array.add("hello"); array.add("world"); /*Windows簡體中文GBK,linux使用UTF-8*/ Files.write(Paths.get("Array.txt"), array, Charset.forName("GBK")); } }
-