IO(Input/Output)流
- IO流用來處理設(shè)備之間的數(shù)據(jù)傳輸
- Java對數(shù)據(jù)的操作是通過流的方式
- Java用于操作流的對象都在IO包中
- 流按操作數(shù)據(jù)分為兩種:字節(jié)流于字符流
- 流按流向分為:輸入流和輸出流
字符流由來就是:早期的字節(jié)流 + 編碼表,為了更便于操作文字?jǐn)?shù)據(jù)
IO流常用基類
所屬包:java.io
- 字節(jié)流的抽象基類(二進(jìn)制)
- InputStream
- OutputStream
- 字符流的抽象基類(文字編碼)
- Reader
- Writer
- 注意:有這四個(gè)類派生出來的子類名稱都是以其父類名字作為子類的后綴记盒,子類的前綴名就是該功能。例如:
- InputStream派生類:FileInputStream
- Reader派生類:FileReader
- OutputStream派生類:FileOutputStream
- Writer派生類:FileWriter
字節(jié)流(char)
FileWriter
需求:將一些文字存儲(chǔ)到硬盤一個(gè)文件中
/* FileWriter
* 要操作文字?jǐn)?shù)據(jù),優(yōu)先考慮字符流
* 從內(nèi)存寫道硬盤使用輸出流Writer,硬盤的數(shù)據(jù)體現(xiàn)是文件
*/
package FileWriter;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator"); // 換行符
public static void main(String[] args) throws IOException {
// 創(chuàng)建一個(gè)可以往文件中寫入字符數(shù)據(jù)的字符輸出流對象
/*
* 既讓是往文件中寫入一個(gè)文字?jǐn)?shù)據(jù)咧擂,那么在創(chuàng)建對象時(shí)宫患,就必須明確該文件(用于存儲(chǔ)數(shù)據(jù)的目的地)
* 如果文件不存在麦到,則會(huì)自動(dòng)創(chuàng)建
* 如果文件存在镀梭,則會(huì)被覆蓋
*/
FileWriter fileWriter = new FileWriter("F:\\demo.txt");
// 調(diào)用Writer對象中的write(String)方法刀森,寫入數(shù)據(jù),放入臨時(shí)緩沖區(qū)
fileWriter.write("hello zimo !");
// 刷新緩沖區(qū)报账,寫入文件中
fileWriter.flush();
// 文件末尾追加文字?jǐn)?shù)據(jù)
fileWriter.append(LINE_SEPARATOR+"hello world !");
// 關(guān)閉流前,會(huì)自動(dòng)刷新緩沖區(qū)后關(guān)閉
fileWriter.close();
// 關(guān)閉后無法操作刷新和寫操作
fileWriter.write("ccc"); // err
FileWriter fileWriter1 = new FileWriter("F:\\demo1.txt",true); // 如果構(gòu)造中加入true,可以對文件進(jìn)行續(xù)寫
fileWriter1.write("aaaaaaa");
fileWriter1.write("bbbbbbb");
fileWriter1.close(); // aaaaaaabbbbbbb
}
}
FileReader
需求:讀取文件內(nèi)容輸出到控制臺上
/* FileReader
* 要操作文字?jǐn)?shù)據(jù)埠偿,優(yōu)先考慮字符流
* 從文件文件讀到磁盤使用輸出流Reader
*/
package IOTest.FileReader;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建一個(gè)讀取字符數(shù)據(jù)流的對象,用讀取流關(guān)聯(lián)一個(gè)已存在文件
FileReader fileReader = new FileReader("f:\\demo.txt");
// 用Reader中的read方法讀取字符,每次讀取一個(gè)字符
int ch = 0;
while ((ch = fileReader.read()) != -1){
System.out.println((char) ch);
}
fileReader.close();
// 用read(char[])讀取文本文件數(shù)據(jù)
FileReader fw = new FileReader("f:\\demo.txt");
char[] buf = new char[1024]; // 1024的整數(shù)倍
int len = 0;
while((len = fw.read(buf)) != -1){
System.out.println(new String(buf, 0, len));
}
}
}
IOException異常處理
package IOTest.IOExceptionCatch;
import java.io.FileWriter;
import java.io.IOException;
public class IOExceptionDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator"); // 換行符
public static void main(String[] args) {
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("Z:\\demo.txt");
fileWriter.write("hello zimo !");
fileWriter.flush();
fileWriter.append(LINE_SEPARATOR + "hello world !");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException("關(guān)閉異常透罢!");
}
}
}
}
}
練習(xí):讀取C盤的文件,寫入到D盤中去
package IOTest.CopyFile;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
// 1.讀取已有的文本文件冠蒋,使用字符讀取流和文件相關(guān)聯(lián)
FileReader fileReader = new FileReader("C:\\TextDemo.txt");
// 2.創(chuàng)建一個(gè)目錄羽圃,用于存儲(chǔ)讀取到的數(shù)據(jù)
FileWriter fileWriter = new FileWriter("D:\\CopyFileDemo.txt");
// 3.頻繁的讀寫操作
EveryCopyByByte(fileReader,fileWriter);
EveryCopyByBuffer(fileReader,fileWriter);
// 4.關(guān)閉流資源
if(fileReader != null)
fileReader.close();
if(fileWriter != null)
fileWriter.close();
}
// 每次讀取一個(gè)緩沖區(qū)
private static void EveryCopyByBuffer(FileReader fileReader, FileWriter fileWriter) {
char[] buff = new char[1024];
int len = 0;
try {
while ((len = fileReader.read(buff)) != -1) {
fileWriter.write(buff, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 每次讀取一個(gè)字符
private static void EveryCopyByByte(FileReader fileReader, FileWriter fileWriter) throws IOException {
int ch = 0;
while ((ch = fileReader.read()) != -1) {
fileWriter.write(ch);
}
}
}
字符流的緩沖區(qū)
- 緩沖區(qū)的出現(xiàn)提高了對數(shù)據(jù)的讀寫效率
- 對應(yīng)類
- BufferedWriter
- BufferedReader
- 緩沖區(qū)要結(jié)合流才可以使用
- 在流的基礎(chǔ)上對流的功能進(jìn)行了增強(qiáng)
BufferedWriter
- newLine():換行符
緩沖區(qū)在緩沖對象時(shí)必須具備緩沖對象(流)
package IOTest.BufferWriter;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("buf.txt");
// 為了提高寫入效率,使用字符流的緩沖區(qū)
// 創(chuàng)建了一個(gè)字符寫入流的緩沖區(qū)對象抖剿,并和指定要被緩沖的對象相關(guān)聯(lián)
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
// bufferedWriter.write("aaaaaaaaaa\r\nbbbbbbbb");
bufferedWriter.write("aaaaaaaaaa");
bufferedWriter.newLine(); // 緩沖區(qū)的換行符
bufferedWriter.write("bbbbbbbb");
// 使用緩沖區(qū)的寫入方法將數(shù)據(jù)寫入到緩沖區(qū)中
bufferedWriter.flush();
// 關(guān)閉緩沖區(qū)朽寞,其實(shí)關(guān)閉了緩沖區(qū)的流對象fileWriter,close();
bufferedWriter.close();
}
}
BufferedReader
- readLine():讀取一行
package IOTest.BufferReader;
import java.io.BufferedReader;
import java.io.FileReader;
public class BurreredWriterDemo {
public static void main(String[] args) {
FileReader fileReader = new FileReader("buf.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = null;
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
}
}
練習(xí):使用緩沖區(qū)拷貝文本文件
package IOTest.BufferRW;
import java.io.*;
public class BufferCopyFileDemo {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("test.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
FileWriter fileWriter = new FileWriter("copy_test.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
/*int ch = 0;
while ((ch = bufferedReader.read()) != -1){
bufferedWriter.write(ch);
}*/
String line = null;
while ((line = bufferedReader.readLine())!= null){
bufferedWriter.write(line);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedReader.close();
bufferedWriter.close();
}
}
練習(xí):自定義讀取緩沖區(qū)
// 模擬BufferedReader
package IOTest.BufferRW;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/*
分析:
* 緩沖區(qū)無非就是封裝了一個(gè)數(shù)組
* 并對外提供了更多的方法對數(shù)組進(jìn)行訪問
* 其實(shí)最終操作的就是數(shù)組的角標(biāo)
原理:
* 從源中獲取一批數(shù)據(jù)裝進(jìn)緩沖區(qū)
* 在緩沖區(qū)中不斷取出一個(gè)個(gè)數(shù)據(jù)
* 在此次取完后识窿,在從源中繼續(xù)取一批數(shù)據(jù)進(jìn)緩沖區(qū)
* 當(dāng)源中的數(shù)據(jù)取完,用-1作為結(jié)束標(biāo)記
*/
public class MyBufferedReader /*extends Reader*/ {
private FileReader fileReader;
/*private Reader reader;*/
// 定一個(gè)數(shù)組作為緩沖區(qū)
private char[] buf = new char[1024];
// 定義一個(gè)指針用于操作這個(gè)數(shù)組中的元素脑融。操作到最后一個(gè)元素喻频,指針歸零
private int ptr = 0;
// 定義一個(gè)計(jì)數(shù)器用于記錄緩沖區(qū)中的數(shù)據(jù)個(gè)數(shù)。當(dāng)該數(shù)據(jù)減到0肘迎,就從源中繼續(xù)獲取數(shù)據(jù)到緩沖區(qū)中
private int count = 0;
MyBufferedReader(FileReader fileReader){
this.fileReader =fileReader;
}
/*
MyBufferedReader(Reader reader){
this.reader =reader;
}
*/
public int myRead() throws IOException {
// 1.從源中獲取一批數(shù)據(jù)到緩沖區(qū)中甥温。需要先判斷計(jì)數(shù)器為0時(shí),才需要從源中獲取數(shù)據(jù)
if (count == 0){
count = fileReader.read(buf);
ptr = 0;
}
if (count < 0)
return -1;
char ch = buf[ptr++];
count--;
return ch;
}
public String myReadLine() throws IOException {
StringBuilder stringBuilder = new StringBuilder();
int ch = 0;
while ((ch = myRead()) != -1){
if (ch == '\r')
continue;
if (ch == '\n')
return stringBuilder.toString();
// 將從緩沖區(qū)讀取到的字符妓布,存儲(chǔ)到緩存行數(shù)據(jù)的緩沖區(qū)中
stringBuilder.append((char)ch);
}
if (stringBuilder.length()!= 0){
return stringBuilder.toString();
}
return null;
}
public void myClose() throws IOException {
fileReader.close();
}
/*
@Override
public int read(char[] cbuf, int off, int len) throws IOException{
return 0;
}
@Override
public void close() throws IOException{
}
*/
}
LineNumberReader:
裝飾類姻蚓,行號讀取追蹤
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("demo.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
// lnr.setLineNumber(100); // 默認(rèn)從0開始,開始讀取一行就變成1匣沼,可以手動(dòng)設(shè)置100
while ((line = lnr.readLine()) != null){
System.out.println(lnr.getLineNumber() + ":" +line);
}
}
裝飾設(shè)計(jì)模式
對一組對象的功能進(jìn)行增強(qiáng)時(shí)狰挡,就可以使用該模式進(jìn)行問題的解決
class Person{
void eat(){
System.out.println("吃飯");
}
}
// 這個(gè)類是為了增強(qiáng)Person而出現(xiàn)的
class NewPerson{
private Person p; // 本質(zhì)還是Person
NewPerson(Person p){
this.p = p;
}
public void eat(){ // 外觀進(jìn)行了升級
System.out.println("開胃酒");
p.eat();
System.out.println("飯后甜點(diǎn)");
}
}
public static void main(String[] args){
Person p = new Person();
NewPerson p1 = new NewPerson(p);
p1.eat();
}
// 繼承同樣可以實(shí)現(xiàn)效果
class NewPersonExtends extends Person{
public void eat(){
System.out.println("開胃酒");
super.eat();
System.out.println("飯后甜點(diǎn)");
}
}
繼承和裝飾的區(qū)別:
- 假設(shè)的基礎(chǔ)體系:
- Writer:
- | -- TextWriter:用于操作文本的流對象
- | -- MediaWriter:用于操作媒體的流對象
想要對操作的動(dòng)作進(jìn)行效率的提高,按照面向?qū)ο笏枷胧吞危梢酝ㄟ^繼承對功能進(jìn)行擴(kuò)展加叁。
- 效率提高需要加入緩沖技術(shù)
- Writer:(繼承實(shí)現(xiàn))
- | -- TextWriter:用于操作文本
- | -- BufferTextWriter:加入了緩沖技術(shù)的操作文本流對象
- | -- MediaWriter:用于操作媒體
- | -- BufferMediaWriter:加入了緩沖技術(shù)的操作媒體流對象
- | -- TextWriter:用于操作文本
如果體系再次進(jìn)行功能擴(kuò)展,又多了一個(gè)流對象枢贿,是否要產(chǎn)生子類殉农?
- 是,這時(shí)就會(huì)發(fā)現(xiàn)只為了提高功能局荚,進(jìn)行的繼承超凳,導(dǎo)致繼承體系越來越臃腫,繼承實(shí)現(xiàn)不夠靈活
加入的都是同一種技術(shù) --- 緩沖技術(shù)
前一種是讓緩沖和具體的對象相結(jié)合耀态,可以將緩沖進(jìn)行單獨(dú)的封裝轮傍,哪個(gè)對象需要緩沖就將哪個(gè)對象和緩沖進(jìn)行關(guān)聯(lián)
- Writer:
- | -- TextWriter:用于操作文本的流對象
- | -- MediaWriter:用于操作媒體的流對象
- | -- BufferWriter:用于提高效率
裝飾比繼承靈活
class Buffer{
// 一次增強(qiáng)一個(gè)流對象的功能
Buffer(TextWriter w){}
Buffer(MediaWriter w){}
}
class BufferWriter extends Writer{
// 一次增強(qiáng)一個(gè)體系的功能
Buffer(Writer w){}
}
字符流(byte)
- 基本操作與字符流類相同
- 但它不僅僅可以操作字符,還可以操作其他媒體文件
- 例子:Copy一個(gè)jpg文件
package ByteStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo {
public static void main(String[] args) throws IOException {
writeDemo();
readDemo();
}
private static void readDemo() throws IOException {
// 1.創(chuàng)建一個(gè)讀取流對象首装,和指定的文件進(jìn)行關(guān)聯(lián)
FileInputStream fileInputStream = new FileInputStream("byteTest.txt");
// 2.讀取字符,一次讀取一個(gè)字符
/*
int ch = 0;
while ((ch = fileInputStream.read()) != -1){
System.out.println((char) ch);
}
// 2.讀取字符,一次讀取一個(gè)指定大小的緩沖區(qū)创夜,建議使用這個(gè)
byte[] buf = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buf)) != -1){
System.out.println(new String(buf, 0, len));
}
*/
// 2.讀取字符,一次讀取一個(gè)剛好的緩沖區(qū)
// fileInputStream.available() 返回一個(gè)文件的字節(jié)大小,慎用仙逻,如果文件太大驰吓,內(nèi)存會(huì)崩潰
byte[] buf = new byte[fileInputStream.available()];
System.out.println(new String(buf));
// 3.關(guān)閉字節(jié)流對象
fileInputStream.close();
}
private static void writeDemo() throws IOException {
// 1.創(chuàng)建字節(jié)輸出流對象,用于操作文件
FileOutputStream fileOutputStream = new FileOutputStream("byteTest.txt");
// 2.寫數(shù)據(jù)系奉,直接寫入到目標(biāo)文件檬贰,flush沒有意義
fileOutputStream.write("hello zimo!".getBytes());
// 緩沖區(qū)需要刷新,字節(jié)流不需要刷新
// fileOutputStream.flush();
// 3.關(guān)閉字節(jié)流對象
fileOutputStream.close();
}
}
練習(xí):復(fù)制Mp3文件
package CopyByte;
import java.io.*;
public class CopyMp3Demo {
public static void main(String[] args) throws IOException {
copyMp3();
copyMp3Buffer();
}
// 緩沖區(qū)緩沖
private static void copyMp3Buffer() throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\大悲咒.mp3");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
FileOutputStream fileOutputStream = new FileOutputStream("C:\\大悲咒-副本.mp3");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
int ch = 0;
while ((ch = bufferedInputStream.read()) != -1){
bufferedOutputStream.write(ch);
// bufferedOutputStream.flush();
}
bufferedInputStream.close();
bufferedOutputStream.close();
}
// 自定義緩沖區(qū)
private static void copyMp3() throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\大悲咒.mp3");
FileOutputStream fileOutputStream = new FileOutputStream("C:\\大悲咒-副本.mp3");
byte[] buf = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buf)) != -1){
fileOutputStream.write(buf,0, len);
}
fileInputStream.close();
fileOutputStream.close();
}
}
不要使用字符流拷貝圖片文件缺亮,可能存在字符解析異常
// 讀取一個(gè)鍵盤錄入的數(shù)據(jù)翁涤,并打印在控制臺上。
public static void main(String[] args) throws IOException {
InputStream inputStream = System.in;
int ch = inputStream.read(); // 阻塞式方法
System.out.println(ch);
inputStream.close(); // 標(biāo)準(zhǔn)流對象只有這一個(gè),建議不用關(guān)葵礼,隨著系統(tǒng)消失自動(dòng)關(guān)閉
InputStream inputStream2 = System.in;
ch = inputStream.read(); // err:標(biāo)準(zhǔn)輸入流已經(jīng)被關(guān)閉了
}
- 標(biāo)準(zhǔn)輸入/輸出設(shè)備流号阿,通常情況下不需要關(guān)閉
public static void main(String[] args) throws IOException {
StringBuilder sb = new StringBuilder()
InputStream inputStream = System.in;
int ch = 0;
while((ch = inputStream.read()) != -1){
if(ch == '\r')continue;
if(ch == '\n'){
String tmp = sb.toString();
if("over".equals(tmp)){
break;
}
System.out.println(tmp.toUpperCase());
sb.delete(0, sb.length());
}else
sb.append((char)ch);
}
}
轉(zhuǎn)換流
1) 將字節(jié)流轉(zhuǎn)成字符流:InputStreamReader(解碼)
public static void main(String[] args){
// 字節(jié)流
InputStream in = System.in;
// 將字節(jié)轉(zhuǎn)成字符的橋梁,轉(zhuǎn)換流
InputStreamReader isr = new InputStreamReader(in);
// 字符流
BufferedReader buffer = new BufferedReader(isr);
String line = null;
while((line - buffer.readLine())!= null){
if("over".equals(line))break;
System.out.println(line.toUpperCase());
}
}
2) 將字符轉(zhuǎn)成字節(jié)流:OutputStreamWriter(編碼)
public static void main(String[] args){
OutputStream out = System.out;
OutputStreamWriter osw = new OutputStreamWriter(out);
String line = null;
osw.write(line.toUpperCase() + "\r\n");
osw.flush(); // 編碼完刷新一下緩沖區(qū)
BufferedWriter buffer = new BufferedWriter(osw);
buffer.write(line.toUpperCase());
buffer.newLine();
buffer.flush();
}
- 簡化代碼
public static void main(String[] args){
BufferedReader buffReader = new BufferedReader(new InputStreamReader(System.in)); // 鍵盤讀入
BufferedWriter buffWriter = new BufferedWriter(new OutputStreamWriter(System.out)); // 輸出到控制臺
//BufferedWriter buffWriter = new BufferedWriter(new FileOutputStream("a.txt")); // 輸出到a.txt
String line = null;
while((line = buffReader.readLine()) != null){
if("over".equals(line))break;
buffWriter.write(line.toUpperCase());
buffWriter.newLine();
buffWriter.flush();
}
}
流的操作基本規(guī)律
-
四個(gè)明確:
-
明確源和目的(匯)
- 源:InputStream鸳粉、Reader
- 目的:OutputStream扔涧、Writer
-
明確數(shù)據(jù)是否是純文本數(shù)據(jù)
-
源:
- 是純文本:Reader
- 不是純文本:InputStream
-
目的:
- 是純文本:Writer
- 不是純文本:OutputStream
-
-
明確具體的設(shè)備
- 源:
- 硬盤:File
- 鍵盤:System.in
- 內(nèi)存:數(shù)組
- 網(wǎng)絡(luò):Socket流
- 目標(biāo):
- 硬盤:File
- 控制臺:System.out
- 內(nèi)存:數(shù)組
- 網(wǎng)絡(luò):Socket流
- 源:
-
是否需要額外功能
- 是否需要高效(緩沖區(qū)): + buffer
- 是否需要轉(zhuǎn)換: + InputStreamReader、OutputStreamWriter
-
如果需求中明確指定碼表編碼的動(dòng)作
- 不能使用FileWriter赁严,因?yàn)閮?nèi)部使用的默認(rèn)本地編碼表
- 只能使用其父類OutputStreamWriter
- OutputStreamWriter接收一個(gè)字符輸出流對象扰柠,既然操作文件,那么應(yīng)該使用FileOutputStream
-
public static void main(String[] args){
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),"UTF-8");
// FileWriter fw = new FileWriter("a.txt"); // 等同于 OutputStreamWriter("a.txt")默認(rèn)構(gòu)造函數(shù)
/**
* FileWriter:實(shí)際上就是默認(rèn)本機(jī)編碼表疼约,默認(rèn)編碼表操作文件的便捷類
* 需要明確指定的編碼卤档,不能使用FileWriter類
*/
osw.write("你好");
osw.close();
}
什么時(shí)候使用轉(zhuǎn)換流?
- 源或目的對應(yīng)設(shè)備是字節(jié)流程剥,但操作的是文本數(shù)據(jù)劝枣,可以作為轉(zhuǎn)換橋梁,提高對文本操作的便捷
- 一旦操作文本涉及到具體指定的編碼表時(shí)织鲸,必須使用轉(zhuǎn)換流
File類
- 用來將文件或者文件夾封裝成對象
- 方便對文件與文件夾的屬性信息進(jìn)行操作
- File對象可以作為參數(shù)傳遞給流的構(gòu)造函數(shù)
- File類中的常用方法
public static void main(String[] args){
// 將一個(gè)已存在或者不存在的文件或者目錄封裝成file對象
File file = new File("c:\\a.txt");
File file1 = new File("c:\\", "a.txt");
File file2 = new File("c:\\");
File file3 = new File(file2, "a.txt");
File file4 = new File("c:" + System.getProperty + "abc" + File.separator + "a.txt");
}
- 常用方法分類:
- 獲忍蛱凇:
- 獲取文件名稱:
String getName()
- 獲取文件路徑:
String getPath() | String getAbsolutePath()
- 獲取文件大小:
Long length()
- 獲取文件修改時(shí)間:
Long lastModified()
- 獲取文件父目錄:
String getParent()
如果是相對路徑搂擦,則獲取不到父目錄
- 獲取文件名稱:
- 創(chuàng)建與刪除:
- 創(chuàng)建文件:
boolean createNewFile()
如果文本不存在則創(chuàng)建稳诚,如果存在不創(chuàng)建 - 創(chuàng)建文件夾:
boolean mkdir() | boolean mkdirs()
- 刪除文件:
boolean delete()
直接刪除boolean deleteOnExit()
結(jié)束后刪除
- 創(chuàng)建文件:
- 判斷:
- 是否存在:
boolean exists()
- 是否文件:
boolean isFile()
- 是否目錄:
boolean isDirectory()
- 是否存在:
- 其他:
- 重命名/剪切:
boolean renameTo(File f1)
- 列出根目錄下文件:
static File listRoots()
- 可用磁盤空間:
long getFreeSpace()
- 總磁盤容量:
long getTotalSpace()
- 已用磁盤空間:
long getUsableSpace()
- 獲取目錄名稱:
String[] list()
包含隱藏文件(如果對象是文件或者是系統(tǒng)級,會(huì)拋出異常) - 獲取目錄對象:
File[] listFiles()
- 重命名/剪切:
- 獲忍蛱凇:
// 文件名過濾器:獲取路徑下所有.java文件
public class FilterByJava implements FilenameFilter{
@Override
public boolean accept(File dir, String name){
return name.endsWith(".java");
}
}
// 文件過濾器:過濾隱藏文件
public class FilterByHidden implements FilenameFilter{
@Override
public boolean accept(File pathname){
return !pathname.isHidden();
}
}
//測試
public static void main(String[] args){
File dir = new File("D:\\");
String[] names = dir.list(new FilterByJava());
for(String name : names){
System.out.println(name);
}
File[] names = dir.list(new FilterByHidden());
for(String name : names){
System.out.println(name);
}
}
深度遍歷文件夾(遞歸方式)
import java.io.File;
public class test {
public static void main(String[] args){
File file = new File("F:\\JavaTest");
int level = 0;
listAll(file ,level);
}
public static void listAll(File file, int level) {
System.out.println(getSpace(level) + file.getName());
level++;
File[] files = file.listFiles();
for (File file1 : files){
if (file1.isDirectory()){
listAll(file1, level);
}else {
System.out.println(getSpace(level) + file1.getName());
}
}
}
private static String getSpace(int level) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("|--");
for (int i = 0; i < level; i++){
// stringBuilder.append("\t");
stringBuilder.insert(0, "|\t");
}
return stringBuilder.toString();
}
}
遞歸:自身直接或間接調(diào)用自身瀑踢。
一個(gè)功能在被重復(fù)使用扳还,并且每次使用時(shí),參與運(yùn)算的結(jié)果和上一次有關(guān)橱夭,可以用遞歸來解決問題
注意:遞歸一定要明確條件氨距,否則容易棧溢出,注意遞歸的次數(shù)
// 刪除一個(gè)有內(nèi)容的目錄
public static void main(String[] args){
File file = new File("E:\\demo");
removeDir(file);
}
public void removeDir(File file){
File[] files = file.listFiles();
for(File f : files){
if(f.isDirectory()){
removeDir(f);
}else{
f.delete();
}
}
file.delete();
}
-
Map
| ---- Hashtable
| ---- Properties:
Properties集合:
- 特點(diǎn):
- 該集合中的鍵和值都是字符串類型
- 集合中的數(shù)據(jù)可以保存到流中棘劣,或者從流中獲取
- 通常該集合用于操作以鍵值對形式存在的配置文件
- 特點(diǎn):
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
// 存儲(chǔ)元素
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","31");
prop.setProperty("wangwu","29");
prop.setProperty("zhaoliu","33");
// 持久化存儲(chǔ)--->> 使用流將文件存儲(chǔ)到文件中
FileOutputStream fos = new FileOutputStream("info.txt");
// 將集合數(shù)據(jù)存儲(chǔ)到文件中去
prop.store(fos, "name : age");
fos.close();
// 加載文件中的數(shù)據(jù)(鍵值對)到集合中
// 使用讀取流
FileInputStream fis = new FileInputStream("info.txt");
prop.load(fis);
prop.list(System.out);
}
模擬Properties.load方法
public static void myLoad() throws IOException{
Properties prop = new Properties();
BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
String line = null;
while((line = bufr.readLine()) != null){
if(line.startsWith("#")) continue;
String[] arr = line.split("=");
prop.setProperty(arr[0], arr[1]);
}
prop.list(System.out);
bufr.close();
}
修改Properties中的某一個(gè)鍵對應(yīng)的值
// 對已有的配置文件中的信息進(jìn)行修改
/**
* 讀取這個(gè)文件
* 將這個(gè)文件中的鍵值數(shù)據(jù)存儲(chǔ)到集合中
* 通過集合對數(shù)據(jù)進(jìn)行修改
* 再通過流將修改后的數(shù)據(jù)存儲(chǔ)到文件中
*/
public static void test() throws IOException{
// 讀取這個(gè)文件
File file = new File("info.txt");
if(!file.exists()){
// 文件不存在
file.createNewFile();
}
FileReader fr = new FileReader("info.txt");
// 創(chuàng)建集合存儲(chǔ)信息
Properties prop = new Properties();
// 將流中的信息存儲(chǔ)到集合中
prop.load();
// 修改
prop.setProperty("wangwu", "16");
FileWriter fw = new FileWriter(file);
prop.store(fw, "");
prop.list(System.out);
fw.close();
fr.close();
}
練習(xí):免費(fèi)試用程序5次俏让,之后請注冊再使用
public static void main(String[] args) throws IOException{
getAppCount();
}
public static void getAppCount() throws IOException{
// 將配置文件封裝成File對象
File countFile = new File("count.properties");
if(!countFile.exists()){
countFile.createNewFile();
}
FileInputStream fis = new FileInputStream(countFile);
Properties prop = new Properties();
prop.load(fis);
// 從集合中獲取鍵的次數(shù)
String value = prop.getProperty("time");
int count = 0;
if(value != null){
count = Integer.parseInt(value);
if(count >= 5){
throw new RuntimeException("使用次數(shù)已到,請注冊茬暇,給錢首昔!");
}
}
count++;
prop.setProperty("time", count + "");
FileOutputStream fos = new FileOutputStream(countFile);
prop.store(fos, "");
fos.close();
fis.close();
}
打印流
- PrintWriter與PrintStream
- 可以直接操作輸入流和文件
PrintStream構(gòu)造函數(shù),接收三種類型的值:
- 字符串路徑
- File對象
- 字節(jié)輸出流
PrintWriter構(gòu)造函數(shù)糙俗,接收三種類型的值:
- 字符串路徑
- File對象
- 字節(jié)輸出流
- 字符輸出流
public static void main(String[] args){
PrintStream out = new PrintStream("print.txt");
out.write(97); // a
out.write(609); // a 只寫最低8位 0000-0000 0000-0000 0000-0010 0110-0001
out.print(97); // 97 將原有字符保持原樣沙廉,然后將數(shù)據(jù)打印到目的地
out.close();
----------------------------------------------------------------------------------------------------
// 字符打印流
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
// PrintWriter out = new PrintWriter(System.out, true); 自動(dòng)刷新緩沖區(qū),無需調(diào)用flush
String line = null;
while((line = bufr.readLine()) != null){
if("exit".equals(line)) break;
out.println(line);
out.flush();
}
out.close();
bufr.close();
}
序列流
- SequenceInputStream
- 多個(gè)流進(jìn)行合并
// 將三個(gè)文件中內(nèi)容放到一個(gè)文件中去
public static void main(String[] args) throws IOException{
/*
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<FileInputStream> en = v.elements();
*/
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int i = 1; i <= 3; i++){
al.add(new FileInputStream(i + ".txt"));
}
final Iterator<FileInputStream> it = al.iterator();
/*
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
@Override
public boolean hasMoreElements(){
return it.hasNext();
}
@Override
public FileInputStream nextElement(){
return it.next();
}
};
*/
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1){
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
文件切割
public static void main(String[] args){
private static final int ONE_M = 1024 * 1024;
File file = new File("C:\\0.bmp");
// 用讀取流關(guān)聯(lián)源文件
FileInputStream fis = new FileInputStream(file);
// 定義一個(gè)1M緩沖區(qū)
byte[] buf = new byte[ONE_M];
// 創(chuàng)建目的
FileOutputStream fos = null;
int len = 0;
int i = 1;
/**
* 記錄切割文件的數(shù)據(jù):名稱臼节、碎片個(gè)數(shù),方便合并
*/
Properties prop = new Properties();
File dir = new File("D:\\partfile");
if(!dir.exists())
dir.mkdirs();
while((len = fis.read(buf))!= -1){
fos = new FileOutputStream(new File(dir, (i++) + ".part"));
fos.write(buf, 0, len);
fos.close();
}
// 將切割文件的信息保存到prop集合中
prop.setProperty("filename", file.getName());
prop.setProperty("partnum", count + "");
fos = new FileOutputStream(new File(dir, count + ".properties"));
// 將prop集合中數(shù)據(jù)存儲(chǔ)到文件中
prop.store(fos,"save file info");
fos.close();
fis.close();
}
文件合并
public static void main(String[] args){
File dir = new File("D:\\partfile");
// 獲取指定目錄下文件配置信息
File[] files = dir.listFile(new SuffixFilter(".properties"));
if(files.length != 1){
throw new RuntimeException(dir + ",該目錄下沒有properties擴(kuò)展名文件或者不唯一");
}
// 記錄配置文件對象
File configFile = files[0];
// 獲取該文件中信息
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(configFile);
prop.load(fis);
String filename = prop.getProperty("filename");
int count = Integer.parseInt(prop.getProperty("partnum"));
// 獲取該目錄下所有的碎片文件
File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
if(partFiles.length != (count - 1)){
throw new RuntimeException("碎片文件不符合,無法合并网缝,應(yīng)該是"+count);
}
// 將碎片文件和流對象關(guān)聯(lián)巨税,并存儲(chǔ)到集合中
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int i = 1; i <= partFiles.length ; i++){
al.add(new FileInputStream(new File(dir, x + ".part")));
}
// 將多個(gè)流合并成一個(gè)序列流
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream(new File(dir, filename));
// 讀寫過程
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1){
fos.write(buf, 0, len);
}
fos.close();
sis.close()
}
// 文件過濾器
public class SuffixFilter implements FilenameFilter{
private String suffix;
public SuffixFilter(String suffix){
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name){
return name.endsWith(suffix);
}
}
操作對象
- ObjectInputStream與ObjectOutputStream
- 被操作的對象需要實(shí)現(xiàn)Serializable(標(biāo)記接口)
public static void main(String[] args) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
// 對象序列化,被序列化對象必須實(shí)現(xiàn)Serializable接口
oos.writeObject(new Person("zimo", 18)); // 不實(shí)現(xiàn)Serializable標(biāo)記接口粉臊,無法寫入
oos.close();
-------------------------------------------------------------------------------------------------
// 對ObjectOutputStream寫入的基本數(shù)據(jù)和對象進(jìn)行反序列化
ObjectInputStream ois = new ObjectInputStream(new FileOutputStream("obj.object"));
Person p = (Person)ois.readObject(); // 以來與Person的class文件 throw ClassNotFountException
System.out.println(p.getName() + ":" + p.getAge());
}
public class Person implements Serializable{
private static final long serialVersionUID = 9527L;
private String name;
private int age;
public Person(String name, int age){
super();
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
Serializable接口
序列化運(yùn)行時(shí)使用一個(gè)serialVersionUID草添,用于反序列化時(shí)驗(yàn)證發(fā)送者和接收者是否為該對象加載的序列化兼容的類
Person{
private transient String name;
private static int age;
}
transient:非靜態(tài)數(shù)據(jù)不想被序列化可以使用這個(gè)關(guān)鍵字修飾
其他類
- RandomAccessFile
- 隨機(jī)訪問文件,自身具備讀寫的方法
- 通過
skipBytes(int x), seek(int x)
來達(dá)到隨機(jī)訪問
- 管道流
- PipedInputStream和PipedOutputStream
- 輸入輸出可以直接進(jìn)行連接扼仲,通過結(jié)合線程使用
- PipedInputStream和PipedOutputStream
// 使用RandomAccessFile對象寫入一些人員信息远寸,比如姓名和年齡
public static void writeFile() throws IOException{
RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw");
raf.write("zhangsan".getBytes());
raf.write(97);
raf.writeInt(609);
//raf.write(609); // 丟棄高位 剩下97
raf.close();
-------------------------------------------------------------------------------------------------------
RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r");
// 通過seek設(shè)置指針的位置,可以進(jìn)行隨機(jī)讀取
raf.seek(0*8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println(name + age);
raf.close();
}
public class PipedStream{
public static void main(String[] args) throws IOException{
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
// 連接管道
input.connect(output);
new Thread(new Input(input)).start();
new Thread(new Output(output)).start();
}
}
class Input implements Runnable{
private PipedInputStream in;
Input(PipedInputStream in){
this.in = in;
}
public void run(){
try{
byte[] buf = new byte[1024];
int len = in.read(buf);
String s = new String(buf, 0, len);
System.out.println("s="+s);
in.close();
}catch(Exception e){
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
Output(PipedOutputStream out){
this.out = out;
}
public void run(){
try{
out.write("管道來了".getBytes());
}catch(Exception e){
}
}
}
- 操作基本數(shù)據(jù)類型
- DataInputStream與DataOutputStream
- 操作字節(jié)數(shù)組
- ByteArrayInputStream與ByteArrayOutputStream
- 關(guān)閉ByteArray(I/O)Stream無效屠凶,關(guān)閉后仍可以使用驰后,不拋出IO異常,只讀取內(nèi)存數(shù)據(jù)矗愧,不占用資源
- 操作字符數(shù)組
- CharArrayReader與CharArrayWrite
- 操作字符串
- StringReader與StringWrite
public static void main(String[] args) throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("你好"); // 代表UTF-8修改版 帶標(biāo)頭 8個(gè)字節(jié)
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
String str = dis.readUTF();
System.out.println(str);
dis.close();
----------------------------------------------------------------------------------------------
ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch = bis.read()) != -1){
bos.write(ch);
}
// 無需關(guān)流
}
編碼表
編碼表的由來
- 計(jì)算機(jī)只能識別二進(jìn)制數(shù)據(jù)灶芝,早期由來是電信號
- 為了方便應(yīng)用計(jì)算機(jī),讓它可以識別各個(gè)國家的文字
- 就將各個(gè)國家的文字用數(shù)字來表示唉韭,并一一對應(yīng)夜涕,形成一張表
- 這就是編碼表
常見的編碼表
- ASCII:美國標(biāo)準(zhǔn)信息交換碼
- 用一個(gè)字節(jié)的7位可以表示
- ISO8859-1:拉丁碼表。歐洲碼表
- 用一個(gè)字節(jié)的8位表示
- GB2312:中國的中文編碼表
- GBK:中國的中文編碼表升級属愤,融合了更多的中文文字符號
- Unicode:國際標(biāo)準(zhǔn)碼女器,融合了多種文字
- 所有文字都用兩個(gè)字節(jié)來表示,Java語言使用的就是Unicode
- UTF-8:最多用三個(gè)字節(jié)來表示一個(gè)字符
- ...
// 簡單的編碼解碼
/**
* 字符串 --->> 字節(jié)數(shù)組:編碼 看的懂 --> 看不懂
* 字節(jié)數(shù)組 --->> 字符串:解碼 看不懂 --> 看得懂
*/
public static void main(String[] args){
String str = "你好";
// 編碼
byte[] buf = str.getBytes();
// byte[] buf = str.getBytes("utf-8"); // -28 -67 -96 -27 -91 -67
for(byte b : buf){
System.out.println(b); // GBK: -60 -29 -70 -61
}
// 解碼
String s1 = new String(buf);
// String s1 = new String(buf, "utf-8");
System.out.println("s1 = " + s1);
}