File介紹
在整個(gè)IO包了,唯一表示與文件本身有關(guān)的類就是File類。使用File類可以進(jìn)行1創(chuàng)建或刪除文件等常用操作。要想使用File類。則首先要觀察File類的構(gòu)造方法,此類的常用構(gòu)造方法如下所示:
No. 方法或常量 類型 描述
- 1 public static final String pathSeparator 常量 表示路徑的分隔符(windows是“;”)
- 2 public static final String separator 常量 表示路徑的分隔符(windows是“\”)
- 3 public File(String pathname) 構(gòu)造 創(chuàng)建File類對(duì)象,傳入完整路徑
- 4 public boolean createNewFile()throws IOException 普通 創(chuàng)建新文件
- 5 public boolean delete() 普通 刪除文件
- 6 public boolean exists() 普通 判斷文件是否存在
- 7 public boolean isDirectory() 普通 判斷給定的路徑是否在一個(gè)目錄
- 8 public long length() 普通 返回文件的大小
- 9 public String[] list() 普通 列出指定目錄的全部?jī)?nèi)容,只是名稱
- 10 public File[] listFiles() 普通 列出指定目錄的全部?jī)?nèi)容,會(huì)有路徑
- 11 Public Boolean mkdir() 普通 創(chuàng)建一個(gè)目錄
- 12 Public Boolean renameTo(File dest) 普通 為已有的文件重命名
代碼:
public static void testFile() throws Exception {
//新建
File hello = new File("J:"+File.separator+"hello.txt");
if (!hello.exists()) {
hello.createNewFile();
}
File hello2 = new File("J:"+File.separator+"hello.txt");
System.out.println(hello2.exists());//說明如果文件存在就使用現(xiàn)有的文件
System.out.println(hello.getAbsolutePath());//J:\hello.txt
System.out.println(hello.getPath());//J:\hello.txt
hello.renameTo(new File("J:\\h.txt"));
//刪除
if (hello.exists()) {
// hello.delete();
}
//新建文件夾
File zhtFiles = new File("J:"+File.separator+"zhtFiles");
if (!zhtFiles.exists()) {
zhtFiles.mkdirs();
}
System.out.println(zhtFiles.getPath());//J:\zhtFiles
//If this abstract pathname is already absolute,
//then the pathname string is simply returned as if by the getPath method.
System.out.println(zhtFiles.getAbsolutePath());//J:\zhtFiles
//新建了多個(gè)文件
for (int i=1; i<11; i++) {
File fi = new File(zhtFiles.getPath() + File.separator +"zht"+i+".txt");
fi.createNewFile();
}
File[] fs = zhtFiles.listFiles();
for (File f : fs) {
System.out.println(f);//帶路徑打印文件名
}
String[] strs = zhtFiles.list();
for (String s : strs) {
System.out.println(s);//只打印文件名
}
if (zhtFiles.isDirectory()) {
zhtFiles.delete();//只能刪除空文件夾
}
deleteFile(zhtFiles.getAbsolutePath());
}
//使用遞歸進(jìn)行文件刪除操作
static void deleteFile(String pathName) {
File file = new File(pathName);
if (!file.exists()) return;//文件不存在
if (!file.isDirectory()) {//是文件
file.delete();
} else {//是文件夾
//刪除文件夾下的文件
File[] fs = file.listFiles();
for (File f : fs) {
deleteFile(f.getAbsolutePath());
}
file.delete();//刪除空文件夾
}
}
IO介紹
IO就相當(dāng)于程序?qū)?shù)據(jù)源的讀入或者寫出的操作方法API的集合。
參考:
http://m.itdecent.cn/p/0b86343232d2
http://www.cnblogs.com/liuhongfeng/p/5175109.html
http://m.itdecent.cn/p/328f4f67714b
IO是輸入和輸出的簡(jiǎn)稱,在實(shí)際的使用時(shí),輸入和輸出是有方向的。就像現(xiàn)實(shí)中兩個(gè)人之間借錢一樣,例如A借錢給B,相對(duì)于A來說是借出,而相對(duì)于B來說則是借入。所以在程序中提到輸入和輸出時(shí),也需要區(qū)分清楚是相對(duì)的內(nèi)容。
在程序中,輸入和輸出都是相對(duì)于當(dāng)前程序而言的,例如從硬盤上讀取一個(gè)配置文件的內(nèi)容到程序中,則相當(dāng)于將文件的內(nèi)容輸入到程序內(nèi)部,因此輸入和“讀”對(duì) 應(yīng),而將程序中的內(nèi)容保存到硬盤上,則相當(dāng)于將文件的內(nèi)容輸出到程序外部,因此輸出和“寫”對(duì)應(yīng)。熟悉輸入和輸出的對(duì)應(yīng)關(guān)系,將有助于后續(xù)內(nèi)容的學(xué)習(xí)。
在Java語言中,輸入和輸出的概念要比其它語言的輸入和輸出的概念涵蓋的內(nèi)容廣泛得多,不僅包含文件的讀寫,也包含網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送,甚至內(nèi)存數(shù)據(jù)的讀寫以及控制臺(tái)數(shù)據(jù)的接收等都由IO來完成。
為了使輸入和輸出的結(jié)構(gòu)保持統(tǒng)一,從而方便程序員使用IO相關(guān)的類,在Java語言的IO類設(shè)計(jì)中引入了一個(gè)新的概念——Stream(流)。
由于在進(jìn)行IO操作時(shí),需要操作的種類很多,例如文件、內(nèi)存和網(wǎng)絡(luò)連接等,這些都被稱作數(shù)據(jù)源(data source),對(duì)于不同的數(shù)據(jù)源處理的方式是不一樣的,如果直接交給程序員進(jìn)行處理,對(duì)于程序員來說則顯得比較復(fù)雜。所以在所有的IO類設(shè)計(jì)時(shí),在讀數(shù)據(jù)時(shí),JDK API將數(shù)據(jù)源的數(shù)據(jù)轉(zhuǎn)換為一種固定的數(shù)據(jù)序列,在寫數(shù)據(jù)時(shí),將需要寫的數(shù)據(jù)以一定的格式寫入到數(shù)據(jù)序列,由JDK API完成將數(shù)據(jù)序列中的數(shù)據(jù)寫入到對(duì)應(yīng)的數(shù)據(jù)源中。這樣由系統(tǒng)完成復(fù)雜的數(shù)據(jù)轉(zhuǎn)換以及不同數(shù)據(jù)源之間的不同的變換,從而簡(jiǎn)化程序員的編碼。
IO的 這種設(shè)計(jì)就和城市中的供水和排水系統(tǒng)設(shè)計(jì)是一樣的,在供水的時(shí)候,水源有江河水、湖水和地下水等不同類型,由自來水公司完成把水源轉(zhuǎn)換為對(duì)應(yīng)的水流(InputStream)。而在 排水系統(tǒng)設(shè)計(jì)時(shí),只需要將污水排入污水管道即可(OutputStream),至于這些污水是怎么被處理的,則不需要關(guān)心,這樣也簡(jiǎn)化了家庭用水的處理。
IO設(shè)計(jì)中這種數(shù)據(jù)序列被形象的稱作流(Stream)。通過使用流的概念,使程序員面對(duì)不同的數(shù)據(jù)源時(shí)只需要建立不同的外殼流即可,不同的外殼流里面都是統(tǒng)一的內(nèi)部流,程序員面對(duì)的就這個(gè)外殼流,外殼流封裝了很方便統(tǒng)一的操作API,而外殼流和內(nèi)部流之間的復(fù)雜轉(zhuǎn)換則由系統(tǒng)完成,從而使程序員不必深入的了解每種數(shù)據(jù)源的讀寫方式,從而降低了IO編程的復(fù)雜度。
如圖所示:

字節(jié)流
流序列中的數(shù)據(jù)既可以是未經(jīng)加工的原始二進(jìn)制數(shù)據(jù),也可以是經(jīng)一定編碼處理后符合某種格式規(guī)定的特定數(shù)據(jù)。因此Java中的流分為兩種:
- 字節(jié)流:數(shù)據(jù)流中最小的數(shù)據(jù)單元是字節(jié)
- 字符流:數(shù)據(jù)流中最小的數(shù)據(jù)單元是字符, Java中的字 符是Unicode編碼,一個(gè)字符占用兩個(gè)字節(jié)。
InputStream(二進(jìn)制格式操作):抽象類,基于字節(jié)的輸入操作,是所有輸入流的父類。定義了所有輸入流都具有的共同特征。
InputStream 為字節(jié)輸入流,它本身為一個(gè)抽象類,必須依靠其子類實(shí)現(xiàn)各種功能,此抽象類是表示字節(jié)輸入流的所有類的超類。 繼承自InputStream 的流都是向程序中輸入數(shù)據(jù)的,且數(shù)據(jù)單位為字節(jié)(8bit);
InputStream是輸入字節(jié)數(shù)據(jù)用的類,所以InputStream類提供了3種重載的read方法.Inputstream類中的常用方法:
(1) public abstract int read( ):讀取一個(gè)byte的數(shù)據(jù),返回值是高位補(bǔ)0的int類型值。若返回值=-1說明沒有讀取到任何字節(jié)讀取工作結(jié)束。
(2) public int read(byte b[ ]):讀取b.length個(gè)字節(jié)的數(shù)據(jù)放到b數(shù)組中。返回值是讀取的字節(jié)數(shù)。該方法實(shí)際上是調(diào)用下一個(gè)方法實(shí)現(xiàn)的
(3) public int read(byte b[ ], int off, int len):從輸入流中最多讀取len個(gè)字節(jié)的數(shù)據(jù),存放到偏移量為off的b數(shù)組中。
(4) public int available( ):返回輸入流中可以讀取的字節(jié)數(shù)。注意:若輸入阻塞,當(dāng)前線程將被掛起,如果InputStream對(duì)象調(diào)用這個(gè)方法的話,它只會(huì)返回0,這個(gè)方法必須由繼承InputStream類的子類對(duì)象調(diào)用才有用,
(5) public long skip(long n):忽略輸入流中的n個(gè)字節(jié),返回值是實(shí)際忽略的字節(jié)數(shù), 跳過一些字節(jié)來讀取
(6) public int close( ) :我們?cè)谑褂猛旰?,必須?duì)我們打開的流進(jìn)行關(guān)閉.
主要的子類(截圖):

- 1) FileInputStream把一個(gè)文件作為InputStream,實(shí)現(xiàn)對(duì)文件的讀取操作
- 2) ByteArrayInputStream:把內(nèi)存中的一個(gè)緩沖區(qū)作為InputStream使用
- 3) StringBufferInputStream:把一個(gè)String對(duì)象作為InputStream
- 4) PipedInputStream:實(shí)現(xiàn)了pipe的概念,主要在線程中使用
- 5) SequenceInputStream:把多個(gè)InputStream合并為一個(gè)InputStream
OutputStream(二進(jìn)制格式操作):抽象類?;谧止?jié)的輸出操作。是所有輸出流的父類。定義了所有輸出流都具有的共同特征。 Java中字符是采用Unicode標(biāo)準(zhǔn),一個(gè)字符是16位,即一個(gè)字符使用兩個(gè)字節(jié)來表示。為此,JAVA中引入了處理字符的流。
OutputStream提供了3個(gè)write方法來做數(shù)據(jù)的輸出,這個(gè)是和InputStream是相對(duì)應(yīng)的。
- 1. public void write(byte b[ ]):將參數(shù)b中的字節(jié)寫到輸出流。
- 2. public void write(byte b[ ], int off, int len) :將參數(shù)b的從偏移量off開始的len個(gè)字節(jié)寫到輸出流。
- 3. public abstract void write(int b) :先將int轉(zhuǎn)換為byte類型,把低字節(jié)寫入到輸出流中。
- 4. public void flush( ) : 將數(shù)據(jù)緩沖區(qū)中數(shù)據(jù)全部輸出,并清空緩沖區(qū)。
- 5. public void close( ) : 關(guān)閉輸出流并釋放與流相關(guān)的系統(tǒng)資源。
主要的子類(截圖):

- ByteArrayOutputStream:把信息存入內(nèi)存中的一個(gè)緩沖區(qū)中
- FileOutputStream:把信息存入文件中
- PipedOutputStream:實(shí)現(xiàn)了pipe的概念,主要在線程中使用
- SequenceOutputStream:把多個(gè)OutStream合并為一個(gè)OutStream
流結(jié)束的判斷:方法read()的返回值為-1時(shí);readLine()的返回值為null時(shí)。
- SequenceOutputStream:把多個(gè)OutStream合并為一個(gè)OutStream
緩沖輸入輸出流 BufferedInputStream/ BufferedOutputStream
計(jì)算機(jī)訪問外部設(shè)備非常耗時(shí)。訪問外存的頻率越高,造成CPU閑置的概率就越大。為了減少訪問外存的次數(shù),應(yīng)該在一次對(duì)外設(shè)的訪問中,讀寫更多的數(shù)據(jù)。為此,除了程序和流節(jié)點(diǎn)間交換數(shù)據(jù)必需的讀寫機(jī)制外,還應(yīng)該增加緩沖機(jī)制。緩沖流就是每一個(gè)數(shù)據(jù)流分配一個(gè)緩沖區(qū),一個(gè)緩沖區(qū)就是一個(gè)臨時(shí)存儲(chǔ)數(shù)據(jù)的內(nèi)存。這樣可以減少訪問硬盤的次數(shù),提高傳輸效率。
BufferedInputStream:當(dāng)向緩沖流寫入數(shù)據(jù)時(shí)候,數(shù)據(jù)先寫到緩沖區(qū),待緩沖區(qū)寫滿后,系統(tǒng)一次性將數(shù)據(jù)發(fā)送給輸出設(shè)備。
BufferedOutputStream :當(dāng)從向緩沖流讀取數(shù)據(jù)時(shí)候,系統(tǒng)先從緩沖區(qū)讀出數(shù)據(jù),待緩沖區(qū)為空時(shí),系統(tǒng)再從輸入設(shè)備讀取數(shù)據(jù)到緩沖區(qū)。
字符流
字符流主要用來處理文本文件。
Reader(文件格式操作):抽象類,基于字符的輸入操作。
Writer(文件格式操作):抽象類,基于字符的輸出操作。
程序:
static void testStream() throws Exception {
//FileInputStream
FileOutputStream fos = new FileOutputStream("J:\\stream1.txt",true);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSS");
String dateStr = sdf.format(new Date()) + "你好啊 " +"\n";
fos.write(dateStr.getBytes("utf-8"));
fos.close();
FileInputStream fis = new FileInputStream("J:\\stream1.txt");
int len = fis.available();
byte[] buf = new byte[len];
fis.read(buf);
// System.out.println(new String(buf, "utf-8"));
dump(new FileInputStream("J:\\stream1.txt"), new FileOutputStream("J:\\n.txt"));
dump(new FileInputStream("J:\\stream1.txt"), new FileOutputStream("J:\\n2.txt"));
//byteArray ByteArrayInputStream 將byte數(shù)組作為數(shù)據(jù)源
//ByteArrayOutputStream 新建的bos對(duì)象內(nèi)部包含了一個(gè)用來存儲(chǔ)數(shù)據(jù)的byte數(shù)組,初始大小32,自動(dòng)增大
//Creates a ByteArrayInputStream so that it uses buf as its buffer array.
byte[] byteSoure = "hello world 你好啊".getBytes("utf-8");
ByteArrayInputStream bis = new ByteArrayInputStream(byteSoure);
//Creates a new byte array output stream.
//The buffer capacity is initially 32 bytes,
//though its size increases if necessary.
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024*10);
byte[] buf2 = new byte[100];
int len2 = 0;
while ((len2 = bis.read(buf2)) != -1) {
bos.write(buf2, 0, len2);
}
System.out.println(new String(bos.toByteArray(), "utf-8"));
//data Stream 在基本的stream上做了一層封裝,可以方便對(duì)各種數(shù)據(jù)類型進(jìn)行讀寫
DataOutputStream dos = new DataOutputStream(new FileOutputStream("J:\\data"));
dos.writeInt(120);
dos.writeFloat(88.45f);
dos.writeUTF("hello data");
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("J:\\data"));
System.out.println(dis.readInt());
System.out.println(dis.readFloat());
System.out.println(dis.readUTF());
//Object Stream 對(duì)類進(jìn)行讀寫,類要實(shí)現(xiàn)serializable接口
Person p1 = new Person("zht", 28);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("J:\\object"));
oos.writeObject(p1);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("J:\\object"));
Person p2 = (Person) ois.readObject();
System.out.println(p2.toString());
//打印類轉(zhuǎn)換成的字符串
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
ObjectOutputStream oos2 = new ObjectOutputStream(bos2);
oos2.writeObject(p1);
System.out.println(new String(bos2.toByteArray()));
}
//文件復(fù)制
static void dump(InputStream scr, OutputStream dest) {
try (InputStream tscr = scr; OutputStream tdest = dest) {//自動(dòng)關(guān)閉
byte[] buf = new byte[1024];
int len = -1;
while ((len = tscr.read(buf)) != -1) {
tdest.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//更高效的復(fù)制
static void dumpHighSpeed(InputStream scr, OutputStream dest) {
try (BufferedInputStream tscr = new BufferedInputStream(scr);
BufferedOutputStream tdest = new BufferedOutputStream(dest)) {//自動(dòng)關(guān)閉
byte[] buf = new byte[1024];
int len = -1;
while ((len = tscr.read(buf)) != -1) {
tdest.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//編輯文檔
static void testWriterReader() throws Exception {
//Reader通過InputStreamReader轉(zhuǎn)換而來,在轉(zhuǎn)換的時(shí)候注意設(shè)置編碼格式
//Writer通過OutputStreamWriter轉(zhuǎn)換而來
InputStreamReader reader = new InputStreamReader(System.in, "gbk");//使用utf-8會(huì)有亂碼
OutputStreamWriter writer = new OutputStreamWriter(System.out, "gbk");
// writer.write("hello 你好");
writer.flush();//控制臺(tái)打印輸出
char[] buf = new char[1024];
//
// int len = reader.read(buf);//從控制臺(tái)讀取數(shù)據(jù)
// writer.write("get:"+new String(buf));
// writer.flush();
//常用 的FileReader FileWriter,因?yàn)椴荒茉O(shè)置編碼格式,建議盡量少用
FileWriter fileWriter1 = new FileWriter("J:\\fw1.txt");//使用系統(tǒng)默認(rèn)編碼
fileWriter1.write("你好zht");
fileWriter1.close();
FileReader fReader1 = new FileReader("J:\\fw1.txt");//使用系統(tǒng)默認(rèn)編碼
fReader1.read(buf);
System.out.println(new String(buf));
//正確的讀寫文件姿勢(shì)
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("J:\\bw1.txt"), "utf-8"));
bufferedWriter.write("你好 bufferWriter");
bufferedWriter.flush();
bufferedWriter.close();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream("J:\\bw1.txt"), "utf-8"));
System.out.println(bufferedReader.readLine());
charSetConvert("J:\\w.txt", "utf-8", "gbk");
}
//文件編碼格式轉(zhuǎn)換
static void charSetConvert(String srcFileName, String readCharSet,
String writeCharSet) throws Exception {
File wFile = new File("J:\\"+new Date().getTime());//臨時(shí)生成新的文件存放編碼轉(zhuǎn)換后的結(jié)果
char[] buf = new char[1024];
int len = 0;
//自動(dòng)關(guān)閉文件
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(srcFileName), readCharSet);
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(wFile), writeCharSet)) {
while ((len = reader.read(buf)) != -1) {//編碼轉(zhuǎn)換
writer.write(buf, 0, len);
}
writer.flush();
//將臨時(shí)生成的文件覆蓋原文件
byte[] bs = new byte[1024];
FileInputStream fis = new FileInputStream(wFile);
FileOutputStream fos = new FileOutputStream(srcFileName);
while ((len = fis.read(bs)) != -1) {
fos.write(bs, 0, len);
}
fos.close();
fis.close();
}
wFile.delete();//刪除臨時(shí)文件
}
class Person implements Serializable {
String name;
int age;
public Person(String n, int a) {
name = n;
age = a;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "["+name+","+age+"]";
}
}