列印流
* 列印流
* 位元組列印流 PrintStream
* 字元列印流 PrintWriter
*
* 列印流的特點:
* A:隻有寫資料,沒有讀資料。隻能操作目的地,不能操作資料源
* B:可以操作任意類型的資料
* print()
* println()
* C:如果啟動了自動重新整理,能夠自動重新整理
* PrintWrite bw = new PrintWriter(new FileWriter/FileOutPutStream("pw2.txt"),true)
* 調用println()的方法才可以
* 這個時候不僅僅自動重新整理了,還實作了資料的換行
* println()
* 等價于
* bw.write();
* bw.newLine();
* bw.flush();
* D:該流是可以直接操作文本檔案的
* 哪些對象是可以直接操作文本檔案的呢?
* FileInputStream
* FileOutputStream
* FileReader
* FileWriter
* PrintWriter
* printStream
* 看API,查流對象的構造方法,如果同時有File類型和String類型的參數,一般來說就是可以直接操作檔案的
*
* 流:
* 基本流:就是能夠直接讀寫檔案的
* 進階流:在基本流操作基礎上提供了一些其他的功能
序列化流和反序列化流
* 序列化:把對象按照流一樣的方式存入文本檔案或者在網絡中傳輸。對象----》流資料(ObjectOutputStream)
* 反序列化:把文本檔案中的流對象資料或者網絡中的流對象資料還原成對象。流資料---》對象(ObjectInputStream)
*
* NotSerializableException:未序列化異常
* 類通過實作 java.io.Serializable
* 接口以啟用其序列化功能。未實作此接口的類将無法使其任何狀态序列化或反序列化。
* 該接口居然沒有任何方法,類似于這種沒有方法的接口被稱為标記接口。
*
* local class incompatible:
* stream classdesc serialVersionUID = -8036188228921520309,
* local class serialVersionUID = -3432617418350035952
*
* 為什麼有問題呢?
* Person類實作了序列化接口,那麼它本身也應該有一個标記值。
* 這個标記值假設是100。
* 開始的時候:
* Person.class -- id=100
* write資料:oos.txt -- id = 100
* read資料:oos.txt -- id = 100
* 現在:
* Person.class -- id = 200
* write資料:oos.txt -- id =100
* read資料:oos.txt -- id = 100
* 我們實際開發中,可能需要使用以前寫過的資料,不能重新寫入。怎麼辦呢?
* 回想一下原因是因為他們的id值不比對。
* 每次修改java檔案的内容的時候,class檔案的id值都會發生變化
* 而讀取檔案的時候,會和class檔案中的id值進行比對。是以就會出問題。
* 但是呢,如果我有辦法讓這個id值在java檔案中是一個固定的值,這樣,你修改檔案的時候,
* 這個id值就不會發生改變,現在的關鍵是我如何知道這個id值如何表示呢?
* 不用擔心,你不用記住也沒關系,滑鼠點選即可。
* 你難道沒有看到黃色警告線嗎?
*
* 我們要知道的是:
* 看到類實作序列化接口的時候,要想解決黃色警告線問題,就可以自動産生一個序列化id值。
* 而且産生這個值以後,我們對類進行任何改動,它讀取以前的資料是沒問題的。
*
* 注意:
* 我一個類中可能有很多的成員變量,有些我不想進行序列化,請問該怎麼辦呢
* 使用transient關鍵字聲明不需要序列化的成員變量
Properties集合
* Properties:屬性集合類,是一個可以和IO流相結合使用的集合類。
* Properties可儲存在流中或從流中加載。屬性清單中每個鍵及其對應值都是一個字元串。
* Properties是Hashtable的子類,說明是一個Map集合
* Properties屬性集合類的特有功能:
* public Object setProperty(String key, String value):添加元素
* public String getProperty(String key):擷取元素
* public Set<String> stringPropertyNames():擷取所有鍵的集合
*
* 這裡的集合必須是Properties集合
* public void load(Reader reader):把檔案中的資料讀取到集合中
* 注意:這個檔案的資料必須是鍵值對形式
* public void store(Writer writer,String comments):把集合中的資料存儲到檔案
commons-IO
Properties、序列化流、列印流大總結
1:登入注冊IO版本案例(掌握)
cn.itcast.pojo User
class User {//【代碼實作】
//成員變量
private String username;
private String password;
//構造方法
public User(){}//無參構造
public User(String username,String password){ //滿帶參構造
this.username = username;
this.password = password;
}
//成員方法setXxx()/getXxx()
public void setUsername(String username){
this.username = username;
}
public String getUsername(){
return username;
}
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return password;
}
}
cn.itcast.dao UserDao
public interface UserDao {//【代碼實作】
public abstract boolean isLogin(String username,String password);
public abstract void regist(User user);
}
cn.itcast.dao.impl UserDaoImpl(實作我不管)
public class UserDaoImpl implements UserDao {//【代碼實作】
private static File file = new File("user.txt");
static {
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("使用者資訊檔案建立失敗");
}
}
@Override
public boolean isLogin(String username, String password) {
BufferedReader br = null;
boolean isRight = false;
try {
br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
String[] arr = line.split("=");
if (arr[0].equals(username) && arr[1].equals(password)) {
isRight = true;
break;
}
}
} catch (FileNotFoundException e) {
System.out.println("使用者資訊檔案找不到,登入失敗");
} catch (IOException e) {
System.out.println("使用者登入失敗");
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
System.out.println("使用者登入資訊釋放資源關閉失敗");
}
}
}
return isRight;
}
@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) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("使用者注冊資訊失敗");
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("注冊資訊釋放資源失敗");
}
}
}
}
}
cn.itcast.game GuessNumber
public class 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("請輸入你猜的數字:");
int guessNumber = sc.nextInt();
count++;
if(number > guessNumber){
System.out.println("你猜的數字"+guessNumber+"小了");
}else if(number<guessNumber){
System.out.println("你猜的數字"+guessNumber+"大了");
}else{
System.out.println("恭喜你猜了"+count+"次猜中了");
break;
}
}
}
}
cn.itcast.test UserTest
public class UserTest {//【代碼實作】
public static void main(String[] args) {
while (true) {
// 歡迎界面,給出選擇項
System.out.println("------o------歡迎光臨------------");
System.out.println("1.登入");
System.out.println("2.注冊");
System.out.println("3.退出");
System.out.println("------------------------------");
Scanner sc = new Scanner(System.in);
// 鍵盤錄入選擇,根據選擇做不同的操作
System.out.println("請輸入你的選擇(1-3):");
// 為了後面的錄入資訊的友善,我所有的資料錄入全部用字元接收
String choice = sc.nextLine();
// switch多個地方要使用,我就定義到外面
UserDao ud = new UserDaoImpl();
switch (choice) {
case "1":
System.out.println("------------登入界面------------");
System.out.println("請輸入使用者名:");
String username = sc.nextLine();
System.out.println("請輸入密碼:");
String password = sc.nextLine();
// UserDao ud = new UserDaoImpl();
boolean success = ud.isLogin(username, password);
if (success) {
System.out.println("登陸成功,可以開始玩猜數字遊戲了");
System.out.println("你玩嗎?y/n");
while (true) {
String s = sc.nextLine();
if ("y".equalsIgnoreCase(s)) {
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);
// 調用注冊功能
// 多态
// UserDao ud = new UserDaoImpl();
// 具體類使用
// UserDao use = new UserDaoImpl();
ud.regist(user);
System.out.println("注冊成功");
break;
case "3":
default:
System.out.println("謝謝使用,再見!");
System.exit(0);
break;
}
}
}
}
2:資料操作流(操作基本類型資料的流)(了解)
(1)可以操作基本類型的資料【byte,short,char,boolean,int,long,double,float】
(2)流對象名稱
DataInputStream readXxx();
DataOutputStream writeXxx();
3:記憶體操作流(了解)
(1)有些時候我們操作完畢後,未必需要産生一個檔案,就可以使用記憶體操作流。
(2)三種
A:ByteArrayInputStream,ByteArrayOutputStream 位元組數組操作流【參數是位元組數組】
B:CharArrayReader,CharArrayWriter 字元數組操作流【參數是字元數組】
C:StringReader,StringWriter 字元串數組操作流【參數是字元串數組】
4:列印流(掌握)
(1)位元組列印流【PrintStream】,字元列印流【PrintWriter】
(2)特點:
A:隻操作目的地,不操作資料源
B:可以操作任意類型的資料
C:如果啟用了自動重新整理,在調用println()方法的時候,能夠換行并重新整理
D:可以直接操作檔案
問題:哪些流可以直接操作檔案呢?
看API,如果其構造方法能夠同時接收File和String類型的參數,一般都是可以直接操作檔案的
(3)複制文本檔案
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();
5:标準輸入輸出流(了解)
(1)System類下面有這樣的兩個字段
public static final InputStream in; 标準輸入流 InputStream is = System.in;
public static final OutputStream out; 标準輸出流 OutputStream os = System.out;
(2)三種鍵盤錄入方式
A:main方法的args接收參數
B:System.in通過BufferedReader進行包裝
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
C:Scanner
Scanner sc = new Scanner(System.in);
(3)輸出語句的原理和如何使用字元流輸出資料
A:原理
System.out.println("helloworld");
等價于
PrintStream ps = System.out;
ps.println("helloworld");
B:把System.out用字元緩沖流包裝一下使用
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
6:随機通路流(了解)【RandomAccessFile】
(1)可以按照檔案指針的位置寫資料和讀資料。
(2)案例:
A:寫資料 write()
B:讀資料 read()
C:擷取和改變檔案指針的位置 long getFilePointer()和void seek(long pos)
7:合并流(了解)
(1)把多個輸入流的資料寫到一個輸出流中。
(2)構造方法:
A:SequenceInputStream(InputStream s1, InputStream s2)
B:SequenceInputStream(Enumeration<? extends InputStream> e)
案例:
* public SequenceInputStream(Enumeration<? extends InputStream> e)
* 通過簡單的回顧我們知道了Enumeration是Vector中的一個方法的傳回值類型。
* Enumeration<E> elements()
*
* Vector<InputStream> v = new Vector<InputStream>();
* InputStream is1 = new FileInputStream("copy2.java");
* ...
* v.addElement(is1);
* ...
* Enumeration<InputStream> en= v.elements();
* SequenceInputStream sis = new SequenceInputStream(en);
* BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("多合并.txt"));
* byte[] bytes = new byte[4096];
* int by;
* while((by = sis.read(bytes))!=-1){
* bos.write(bytes, 0, by);
* bos.flush();
* }
* bos.close();
* sis.close();
8:序列化流(了解)【ObjectInputStream&&ObjectOutputStream】
(1)可以把對象寫入文本檔案或者在網絡中傳輸
(2)如何實作序列化呢?
讓被序列化的對象所屬類實作序列化接口。
該接口是一個标記接口。沒有功能需要實作。
(3)注意問題:
把資料寫到檔案後,如果再去修改類會産生一個問題。
如何解決該問題呢?
在類檔案中,給出一個固定的序列化id值。
而且,這樣也可以解決黃色警告線問題
如果對象中的某個屬性不想被序列化,加關鍵字transient修飾,該對象就不能被序列化了。
(4)面試題:
什麼是序列化? 将對象------轉換成-----》流資料
如何實作序列化? 讓被序列化的對象所屬類去實作序列化接口
什麼是反序列化? 将流資料------轉換成-----》對象
9:Properties(了解)
(1)是一個集合類,Hashtable的子類
(2)特有功能
A:public Object setProperty(String key,String value):添加元素
B:public String getProperty(String key):根據鍵擷取值
C:public Set<String> stringPropertyNames():擷取所有的鍵
案例:
//建立集合對象
Properties prop = new Properties();
//添加元素
prop.setProperty("張三", "30");
prop.setProperty("李四", "40");
prop.setProperty("王五", "50");
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key+"-----"+value);
}
(3)和IO流結合的方法
把鍵值對形式的文本檔案内容加載到集合中
public void load(Reader reader)
public void load(InputStream inStream)
把集合中的資料存儲到文本檔案中
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
(4)案例:
A:根據給定的檔案判斷是否有鍵為"lisi"的,如果有就修改其值為100
//A:把檔案中的資料加載到集合中
//建立集合對象
Properties prop = new Properties();
//建立字元輸入流對象
Reader r = new FileReader("prop.txt");
//将檔案中的資料加載到集合
prop.load(r);
//釋放資源
r.close();
//B:周遊集合,擷取得到每一個鍵
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
//C:判斷鍵是否有“lisi”的,如果有就修改其值為“100”
if("lisi".equals(key)){
prop.setProperty(key, "100");
}
}
//D:把集合中的資料重新存儲到檔案中
Writer w = new FileWriter("prop.txt");
prop.store(w, null);
w.close();
B:寫一個程式實作控制猜數字小遊戲程式不能玩超過5次
// 把鍵值對形式的文本檔案内容加載到集合中
Reader r = new FileReader("count.txt");
Properties prop = new Properties();
prop.load(r);
r.close();
String value = prop.getProperty("count");
int number = Integer.parseInt(value);
if(number>5){
System.out.println("遊戲試玩已結束,請付費。");
System.exit(0);
}else{
number++;
GuessNumber.start();
//把集合中的資料存儲到文本檔案中
prop.setProperty("count", String.valueOf(number));
Writer w = new FileWriter("count.txt");
prop.store(w, null);
w.close();
}
10:NIO(了解)
(1)JDK4出現的NIO,對以前的IO操作進行了優化,提供了效率。但是大部分我們看到的還是以前的IO
(2)JDK7的NIO的使用
Path:路徑
Paths:通過靜态方法傳回一個路徑
Files:提供了常見的功能
複制文本檔案
把集合中的資料寫到文本檔案