一详瑞、創(chuàng)建文件
File file = new File("D:/yunqingPojects/lol.txt"); // 可以用絕對(duì)路徑或者相對(duì)路徑創(chuàng)建
file.getParentFile().mkdirs();
file.createNewFile();
二、流 的概念
1.為什么需要流臣缀?
不同介質(zhì)之間數(shù)據(jù)交互蛤虐,比如讀取硬盤上文件到程序中
數(shù)據(jù)源可以是文件,數(shù)據(jù)庫(kù)肝陪,網(wǎng)絡(luò)甚至是其他的程序
2.輸入流or輸出流 - 默認(rèn)是站在程序的角度來(lái)說(shuō)來(lái)說(shuō)輸入輸出
e.g.從文件中讀數(shù)據(jù) 就是輸入流
三驳庭、ASCII碼 的概念
所有的數(shù)據(jù)存放在計(jì)算機(jī)中都是以數(shù)字的形式存放的。 所以字母就需要轉(zhuǎn)換為數(shù)字才能夠存放氯窍。
包含簡(jiǎn)單的英文字母饲常,符號(hào),數(shù)字等等狼讨。 不包含中文贝淤,德文,俄語(yǔ)等復(fù)雜的政供。
四播聪、字節(jié)流(InputStream,OutputStream)
InputStream,OutputStream都是抽象類;
FileInputStream 是InputStream子類;FileOutputStream 是OutputStream子類
- 以字節(jié)流的形式讀取文件內(nèi)容(即 將文件數(shù)據(jù)讀取到
中):
try {
//準(zhǔn)備文件lol.txt其中的內(nèi)容是AB,對(duì)應(yīng)的ASCII分別是65 66
File f =new File("d:/lol.txt");
//創(chuàng)建基于文件的輸入流
FileInputStream fis =new FileInputStream(f);
//創(chuàng)建字節(jié)數(shù)組布隔,其長(zhǎng)度就是文件的長(zhǎng)度
byte[] all =new byte[(int) f.length()];
//以字節(jié)流的形式讀取文件所有內(nèi)容
fis.read(all);
for (byte b : all) {
//打印出來(lái)是65 66
System.out.println(b);
}
//每次使用完流离陶,都應(yīng)該進(jìn)行關(guān)閉
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
- 以字節(jié)流的形式向文件寫入數(shù)據(jù)(即 通過(guò)
的形式向文件寫數(shù)據(jù))::
try {
// 準(zhǔn)備文件lol2.txt其中的內(nèi)容是空的
File f = new File("d:/lol2.txt");
// 準(zhǔn)備長(zhǎng)度是2的字節(jié)數(shù)組,用88,89初始化衅檀,其對(duì)應(yīng)的字符分別是X,Y
byte data[] = { 88, 89 };
// 創(chuàng)建基于文件的輸出流
FileOutputStream fos = new FileOutputStream(f);
// 把數(shù)據(jù)寫入到輸出流
fos.write(data);
// 關(guān)閉輸出流
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
五招刨、關(guān)閉流的方式
把流定義在try()里,try,catch或者finally結(jié)束的時(shí)候,會(huì)自動(dòng)關(guān)閉哀军。
JDK7之后沉眶,所有的流都實(shí)現(xiàn)了一個(gè)接口叫做 AutoCloseable打却,任何類實(shí)現(xiàn)了這個(gè)接口,都可以在try()中進(jìn)行實(shí)例化谎倔。 并且在try, catch, finally結(jié)束的時(shí)候自動(dòng)關(guān)閉柳击,回收相關(guān)資源。
public static void main(String[] args) {
File f = new File("d:/lol.txt");
//把流定義在try()里,try,catch或者finally結(jié)束的時(shí)候片习,會(huì)自動(dòng)關(guān)閉
try (FileInputStream fis = new FileInputStream(f)) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
六腻暮、字符流(Reader,Writer)
Reader,Writer都是抽象類
FileReader 是Reader子類,FileWriter 是Writer的子類
- 使用字符流讀取文件(以
為基礎(chǔ))
public static void main(String[] args) {
// 準(zhǔn)備文件lol.txt其中的內(nèi)容是AB
File f = new File("d:/lol.txt");
// 創(chuàng)建基于文件的Reader
try (FileReader fr = new FileReader(f)) {
// 創(chuàng)建字符數(shù)組毯侦,其長(zhǎng)度就是文件的長(zhǎng)度
char[] all = new char[(int) f.length()];
// 以字符流的形式讀取文件所有內(nèi)容
fr.read(all);
for (char b : all) {
// 打印出來(lái)是A B
System.out.println(b);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
- 使用字符流把數(shù)據(jù)寫入到文件(以
為基礎(chǔ))
public static void main(String[] args) {
// 準(zhǔn)備文件lol2.txt
File f = new File("d:/lol2.txt");
// 創(chuàng)建基于文件的Writer
try (FileWriter fr = new FileWriter(f)) {
// 以字符流的形式把數(shù)據(jù)寫入到文件中
String data="abcdefg1234567890";
char[] cs = data.toCharArray();
fr.write(cs);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
七哭靖、中文問(wèn)題
1.編碼概念:
-
計(jì)算機(jī)上的所有的數(shù)據(jù)都是以數(shù)字的形式進(jìn)行存儲(chǔ)的。
那么一個(gè)文件到底在硬盤上是由哪些數(shù)字組成的侈离,取決于用的什么編碼方式(可以理解為:文件中存儲(chǔ)的都是對(duì)應(yīng)棋盤的坐標(biāo))
字符編碼的理解.png 同一個(gè)字符在不同的坐標(biāo)體系中坐標(biāo)是不一樣的试幽,即在硬盤中的實(shí)際數(shù)值不一樣
2.常見編碼方式
工作后經(jīng)常接觸的編碼方式有如下幾種:
ISO-8859-1 ASCII 數(shù)字和西歐字母
GBK GB2312 BIG5 中文
UNICODE (統(tǒng)一碼,萬(wàn)國(guó)碼)
其中
ISO-8859-1 包含 ASCII
GB2312 是簡(jiǎn)體中文卦碾,BIG5是繁體中文铺坞,GBK同時(shí)包含簡(jiǎn)體和繁體以及日文。
UNICODE 包括了所有的文字洲胖,無(wú)論中文济榨,英文,藏文绿映,法文擒滑,世界所有的文字都包含其中
3.用 字節(jié)流 正確讀取中文
為了能夠正確的讀取中文內(nèi)容
1>. 必須了解文本是以哪種編碼方式保存字符的
2>. 使用字節(jié)流讀取了文本后,再使用對(duì)應(yīng)的編碼方式去識(shí)別這些數(shù)字叉弦,得到正確的字符.
如本例丐一,一個(gè)文件中的內(nèi)容是字符,編碼方式是GBK淹冰,那么讀出來(lái)的數(shù)據(jù)一定是D6D0库车。
再使用GBK編碼方式識(shí)別D6D0,就能正確的得到字符
public static void main(String[] args) {
File f = new File("E:\\project\\j2se\\src\\test.txt");
try (FileInputStream fis = new FileInputStream(f);) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
//文件中讀出來(lái)的數(shù)據(jù)是
System.out.println("文件中讀出來(lái)的數(shù)據(jù)是:");
for (byte b : all)
{
int i = b&0x000000ff; //只取16進(jìn)制的后兩位
System.out.println(Integer.toHexString(i));
}
System.out.println("把這個(gè)數(shù)字樱拴,放在GBK的棋盤上去:");
String str = new String(all,"GBK");
System.out.println(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
4.用 字符流 正確讀取中文
FileReader得到的是字符柠衍,所以一定是已經(jīng)把字節(jié) 了
而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統(tǒng)晶乔,就是GBK
FileReader是不能手動(dòng)設(shè)置編碼方式的珍坊,為了使用其他的編碼方式,只能使用InputStreamReader來(lái)代替瘪弓,像這樣:
new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"));
在本例中垫蛆,用記事本另存為UTF-8格式,然后用UTF-8就能識(shí)別對(duì)應(yīng)的中文了腺怯。
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
File f = new File("E:\\project\\j2se\\src\\test.txt"); // 此處文件是以UTF8 的編碼方式存儲(chǔ)的一個(gè) "中"字
//FileReader是不能手動(dòng)設(shè)置編碼方式的袱饭,為了使用其他的編碼方式,只能使用InputStreamReader來(lái)代替
//并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 這樣的形式
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
char[] cs = new char[(int) f.length()];
isr.read(cs);
System.out.printf("InputStreamReader 指定編碼方式UTF-8,識(shí)別出來(lái)的字符是:%n");
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
八呛占、緩存流
- 為什么出現(xiàn)了緩存流(BufferedReader,PrintWriter)
- 字符流 和 字節(jié)流 每一次讀寫的時(shí)候 都會(huì)訪問(wèn)硬盤虑乖,性能不佳
- 緩存流 在讀取的時(shí)候,會(huì)一次性讀較多的數(shù)據(jù)到緩存中晾虑,以后每一次的讀取疹味,都是在緩存中訪問(wèn),直到緩存中的數(shù)據(jù)讀取完畢帜篇,再到硬盤中讀炔谵唷;
緩存流 在寫入數(shù)據(jù)的時(shí)候笙隙,會(huì)先把數(shù)據(jù)寫入到緩存區(qū)洪灯,直到緩存區(qū)達(dá)到一定的量,才把這些數(shù)據(jù)一起寫入到硬盤中去竟痰。按照這種操作模式签钩,就不會(huì)像字節(jié)流,字符流那樣每寫一個(gè)字節(jié)都訪問(wèn)硬盤坏快,從而減少了IO操作 - 就好比吃飯铅檩,不用緩存就是
。用緩存就是
- 緩存流必須建立在一個(gè)存在的流的基礎(chǔ)上
2.使用緩存流寫入數(shù)據(jù)
PrintWriter 緩存字符輸出流, 可以一次寫出一行數(shù)據(jù)
API:pw.println()
public void testCacheStrem(){
// 向文件lol3.txt中寫入三行語(yǔ)句
File f = new File("D:/pojects/lol3.txt");
try (FileWriter fw = new FileWriter(f);PrintWriter pw = new PrintWriter(fw)) {
pw.println("garen kill teemo");
pw.println("teemo revive after 1 minutes");
pw.println("teemo try to garen, but killed again");
}catch (IOException e){
e.printStackTrace();
}
}
3.使用緩存流讀取數(shù)據(jù)
BufferedReader 緩存字符輸入流祥得,可以一次讀取一行數(shù)據(jù)
br.readLine()
public void testCacheStremRead(){
// 從文件lol3.txt中寫入三行語(yǔ)句
File f = new File("D:/pojects/lol3.txt");
try (FileReader fr = new FileReader(f);BufferedReader br = new BufferedReader(fr)) {
while (true){
String line = br.readLine();
if (line == null) break;
System.out.println(line);
}
}catch (IOException e){
e.printStackTrace();
}
}
- 強(qiáng)制寫入硬盤 flush()
有的時(shí)候臼予,需要立即把數(shù)據(jù)寫入到硬盤,而不是等緩存滿了才寫出去啃沪。 這時(shí)候就需要用到flush
public static void main(String[] args) {
//向文件lol2.txt中寫入三行語(yǔ)句
File f =new File("d:/lol2.txt");
//創(chuàng)建文件字符流
//緩存流必須建立在一個(gè)存在的流的基礎(chǔ)上
try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
pw.println("garen kill teemo");
//強(qiáng)制把緩存中的數(shù)據(jù)寫入硬盤粘拾,無(wú)論緩存是否已滿
pw.flush();
pw.println("teemo revive after 1 minutes");
pw.flush();
pw.println("teemo try to garen, but killed again");
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
九、數(shù)據(jù)流(DataInputStream,DataOutputStream)
1.What for
如果向文件中先后寫入一個(gè)浮點(diǎn)數(shù)11.3 和一個(gè)整數(shù)38创千,那么文件中的內(nèi)容為11.338缰雇,
需要自己添加特殊字符進(jìn)行在寫入的時(shí)候插入才能在讀取的時(shí)候判別第一次寫的浮點(diǎn)數(shù)和第二次寫的整數(shù)。
數(shù)據(jù)流幫我們進(jìn)行了維護(hù)追驴。
2.用數(shù)據(jù)流直接進(jìn)行數(shù)字的讀寫
public void testDataStream(){
// 向文件中順序?qū)懭雰蓚€(gè)數(shù)字械哟,然后順序讀出
write();
read();
}
public void write(){
File f = new File("D:/yunqingPojects/lol3.txt");
try (FileOutputStream fos = new FileOutputStream(f);DataOutputStream dos = new DataOutputStream(fos)) {
dos.writeFloat(11.2f);
dos.writeInt(30);
}catch (IOException e){
}
}
public void read(){
File f = new File("D:/yunqingPojects/lol3.txt");
try (FileInputStream fis = new FileInputStream(f);DataInputStream dis = new DataInputStream(fis)) {
float num1 = dis.readFloat();
int num2 = dis.readInt();
System.out.println(num1);
System.out.println(num2);
}catch (IOException e){
}
}
十、對(duì)象流( ObjectInputStream,ObjectOutputStream)
對(duì)象流指的是可以直接把一個(gè) 給其他的介質(zhì)殿雪,比如硬盤 暇咆。
一個(gè)對(duì)象以流的形式進(jìn)行傳輸叫做。 該對(duì)象所對(duì)應(yīng)的類,必須是實(shí)現(xiàn)Serializable接口爸业。
2.API:
oos.writeObject(h); // 將對(duì)象寫入文件
Hero h2 = (Hero) ois.readObject(); // 將對(duì)象從文件讀出
2.例子
創(chuàng)建一個(gè)Hero對(duì)象其骄,設(shè)置其名稱為garen。
把該對(duì)象序列化到一個(gè)文件garen.lol扯旷。然后再通過(guò)序列化把該文件轉(zhuǎn)換為一個(gè)Hero對(duì)象
public void testObjStream(){
Hero hero = new Hero();
hero.name = "gareen";
hero.hp = 616;
File f = new File("D:/yunqingPojects/lol4.txt");
try (
// 創(chuàng)建對(duì)象輸出流
FileOutputStream fos = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(fos);
//創(chuàng)建對(duì)象輸入流
FileInputStream fis = new FileInputStream(f);ObjectInputStream ois = new ObjectInputStream(fis)) {
oos.writeObject(hero);
Hero h = (Hero) ois.readObject();
System.out.println(h.name);
System.out.println(h.hp);
}catch (IOException ex){
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
十一拯爽、控制臺(tái)輸入流(System.in,Scanner)
1.System.in
public static void main(String[] args) {
// 控制臺(tái)輸入
try (InputStream is = System.in;) {
while (true) {
// 敲入a,然后敲回車可以看到
// 97 13 10
// 97是a的ASCII碼
// 13 10分別對(duì)應(yīng)回車換行
int i = is.read();
System.out.println(i);
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.Scanner讀取字符串(sc..nextLine())
使用System.in.read雖然可以讀取數(shù)據(jù)钧忽,但是很不方便,
使用Scanner就可以逐行讀取了
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
while(true){
String line = s.nextLine();
System.out.println(line);
}
}
3.Scanner從控制臺(tái)讀取整數(shù)(sc.nextInt())
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int a = s.nextInt();
System.out.println("第一個(gè)整數(shù):"+a);
int b = s.nextInt();
System.out.println("第二個(gè)整數(shù):"+b);
}