java.io包提供了大量的流類,其中全部輸入流都是InputStream抽象類(字節輸入流)和Reader抽象類(字符輸入流)的子類,而全部的輸出流都是OutputStream抽象類(字節輸出流)和Writer抽象類(字符輸出流)的子類。java
File類:(處理文件和目錄)
File對象主要獲取文件自己的屬性,如文件目錄、文件長度、和文件讀寫權限等,不涉及對文件內容的讀寫操做。
建立File對象的構造方法有以下三個:
File(String filename)
File(String directoryPath, String filename)
File(File f, String filename) //f是制定一個目錄的文件程序員
文件的屬性:
常用File類下列方法獲取文件自己一些信息:
public String getName() //獲取文件名
public boolean canRead() //判斷文件是否可讀
public boolean canWrite() //判斷文件是否可寫
public boolean exists() //判斷文件是否存在
public long length() //獲取文件長度(字節單位)
public String getAbsolutePath() //獲取文件絕對路徑
public String getParent() //獲取文件父目錄
public boolean isFile() //判斷文件是不是一個正常文件,而不是目錄
public boolean isDirectory() //判斷文件是不是一個(已存在)目錄
public boolean isHidden() //判斷文件是不是隱藏文件
public long lastModified() //獲取文件最後修改時間(時間是從1970年午夜至文件最後修改時刻的毫秒數)windows
目錄:
一、建立目錄:
使用File對象調用方法public boolean mkdir()可建立一個目錄,成功建立返回true,不然返回false(若是該目錄已經存在則返回false)。數組
二、列出目錄中文件:
若是File對象是一個目錄,該對象能夠調用下列方法列出該目錄下的文件和子目錄。
public String[] list() //用字符串形式返回目錄下的所有文件
public File[] listFiles() //用File對象形式返回目錄下的所有文件緩存
文件過濾器:
有時須要列出目錄下指定類型文件,可以使用File類的兩個方法,以下:、
public String[] list(FilenameFilter obj)
public File[] listFiles(FilenameFilter obj)
FilenameFilter是一個接口,該接口有一個方法:
public boolean accept(File dir, String name)
使 用list方法時,須要想該方法傳遞一個實現FilenameFilter接口的對象。list方法執行時,參數不斷回調接口方法accept(File dir, String name),參數name是實例化目錄的一個文件名,參數dir爲調用list的當前目錄,當接口方法返回true時,list方法就將目錄dir中的文 件存放到返回的數組中。app
例子:(列出當前目錄下所有java文件名稱)
import java.io.*;
public class test1 {
public test1() {
// TODO 自動生成構造函數存根
}
public static void main(String[] args) {
File dir = new File("."); //系統中"."表示當前目錄,".."表示當前上一級目錄,("\"爲根目錄,但爲了轉義表示爲"\\")
FileAccept acceptCondition = new FileAccept("java");
String[] fileName = dir.list(acceptCondition);
for(int i=0; i<fileName.length; i++){
System.out.println(fileName[i]);
}
}
}dom
public class FileAccept implements FilenameFilter {
String str = null;
public FileAccept(String s) {
// TODO 自動生成構造函數存根
str = "."+s;
}
public boolean accept(File dir, String name) {
// TODO 自動生成方法存根
return name.endsWith(str);
}
}函數
文件的建立與刪除:(以下例)
File f = new File("c:\\","letter.dat"); //先用File類建立一個文件對象。
if(!f.exists()){ //若是該文件夾中沒有該文件,就新建一個
try{
f.createNewFile();
}
catch(IOException e){
}
}工具
if(f.exists()){ //若是存在該文件,就刪除。也能夠之間用f.deleteOnExit()方法。
f.delete();
}this
運行可執行文件:
要運行一個可執行文件,用java.lang.Runtime類。
先用Runtime類聲明一個對象,如:
Runtime run;
而後用該類的類方法getRuntime()建立這個對象,如:
run = Runtime.getRuntime();
其中run能夠調用exec(String command)方法打開本地機子上的可執行文件或執行一個操做。
示例以下:
try{
Runtime run = Runtime.getRuntime();
File file = new File("c:\\windows","Notepad.exe");
run.exec(file.getAbsolutePath());
}
catch(Exception e){
System.out.println(e);
}
字節輸入輸出流類:(FileInputStream類和FileOutputStream類)
當文件讀取需求比較簡單時,可以使用FileInputStream類,該類派生於InputStream類。
FileInputStream類經常使用構造方法兩個:
FileInputStream(String name) //使用給定文件名name建立FileInputStream對象
FileInputStream(File file) //使用File對象建立FileInputStream對象
使用FileInputStream文件輸入流對象讀取文件,示例以下:
FileInputStream istream = new FileInputStream("hello.txt");
或
File file = new File("hello.txt");
FileInputStream istream = new FileInputStream(file);
處理I/O異常:
使用文件輸入流構造方法建立對象可能會出現錯誤,如要打開的文件不存在等,使用IOException對象表示這個出錯信號。程序必須捕獲處理這個異常。相似以下:
try {
FileInputStream istream = new FileInputStream("hello.txt");
}
catch(IOException e) {
System.out.println("File read error:"+e);
}
(I/O操做對於錯誤特別敏感,全部許多流類的構造方法和讀寫方法都會引發I/O異常,程序必須捕獲處理這些異常。)
從輸入流讀取字節:
輸入流調用read()方法從輸入流中讀出數據。方法以下:
int read(); //順序讀取源中單個字節數據,返回字節值(0-255整數),若是到達源末尾,返回-1。
int read(byte b[]); //讀取b.length個字節,存放在數組b中,返回實際讀取的字節數。
int read(byte b[], int off, int len) //讀取len個字節,存放在數組b中,off是首字節在數組中的存放位置,返回實際讀取字節數。
(read()方法順序讀取文件,只要流不關閉,每次調用read()方法就順序讀取源中其他內容,直到源的末尾或流關閉!)
關閉流:
使用完流關閉它是個好習慣,儘管java在程序結束時會自動關閉全部打開的流。由於一個被打開的流可能會用盡系統資源,這取決 與平臺和實現。若是不關閉被打開的流,就可能不容許另外一個程序操做利用這些流所用的資源。關閉輸出流的另外一個緣由是保證操做系統把流緩衝區的數據寫到磁盤 上(目的地)。
能夠用文件輸入/輸出流對象調用close()方法關閉流。
FileOutputStream類與FileInputStream類對應。構造方法及其使用與FileOInputStream一致。
能夠用輸出流對象調用write方法把字節寫入到輸出流,到達目的地。以下:
public void write(int b) //將指定字節寫到輸出流
public void write(byte b[]) //寫b.length個字節到輸出流
public void write(byte b[], int off, int len) //從字節數組b中起始於偏移量off處寫入len個字節到輸出流
(FileOutputStream流順序地寫文件,只要不關閉流,每次調用write()方法就順序地向輸出流寫入數據,直到流關閉!)
字符輸入輸出流類:(FileReader類和FileWriter類)
字節輸入輸出流類以字節單位讀寫數據,不能很好的操做Unicode字符。若是使用字符流就不容易出現亂碼問題。
FileReader和FileWriter分別是Reader和Writer的子類,構造方法以下:
FileReader(String name); FileReader(File file);
FileWriter(String name); FileWriter(File file);
字符輸入/輸出流的read()和Write()方法使用字符數組讀寫數據,以字符(char)爲基本單位。經常使用方法以下:
int read() //從源中讀取一個字符,返回一個Unicode字符值(0-65535整數),未讀出字符返回-1。
int read(char b[])
int read(char b[], int off, int len)
void write(int n) //向目的地寫入一個字符(Unicode字符值)
void write(char b[])
void write(char b[], int off, int len)
BufferedReader類和BufferedWriter類:
當須要每次讀寫一行,沒法知道一行有多少字符,即字符數組大小沒法肯定,這時FileReader,FileWriter類就很難完成這樣的任務。
java 中用BufferedReader和BufferedWriter流能夠完成這樣的工做。兩者的源和目的地必須是字符輸入流和字符輸出流。所以,能夠把 Reader(字符輸入流)做爲BufferedReader流的源,把Writer(字符輸出流)流做爲BufferedWriter流的目的地。
構造方法以下:
BufferedReader(Reader in);
BufferedWriter(Writer out);
用BufferedReader類對象調用readLine()方法讀取文本行:
FileReader filereader = new FileReader("Student.txt");
BufferedReader in = new BufferedReader(filereader);
String strLine = in.readLine();
相似的,能夠將BufferedWriter流和FileWriter流鏈接在一塊兒,而後使用BufferedWriter流將數據寫到目的地,如:
FileWriter filewriter = new FileWriter("Student.txt");
BufferedWriter out = new BufferedWriter(filewriter);
而後輸出使用BufferedWriter類的方法,如:
write(String s, int off, int len) //把字符串s寫到Student.txt中,off是s開始處的偏移量,len是寫入的字符數量。
可 以把BufferedReader和BufferedWriter稱做上層流,把它們指向的字符流稱做底層流。java採用緩存技術將上層流和底層流連 接。底層字符輸入流先把數據讀入緩存,BufferedReader流再從緩存讀取數據;BufferedWriter流將數據寫入緩存,底層字符輸出流 會不斷地將緩存中的數據寫到目的地。
當BufferedWriter流調用flush()方法刷新緩存或調用close()方法關閉時,即便緩存尚未溢滿,底層流也會馬上將緩存的數據寫到目的地。
RandomAccessFile類:
Java提供了更完善的用來處理文件輸入輸出操做功能的RandomAccessFile流,該流的指向既能夠做爲源也能夠做爲目的地,也就是說對一個文件進行讀寫操做時,建立一個指向文件的RandomAccessFile流便可。
RandomAccessFile類兩個構造方法:
RandomAccessFile(String name, String mode) //mode取r(只讀)或rw(可讀寫)
RandomAccessFile(File file, String mode) //mode取r(只讀)或rw(可讀寫)
RandomAccessFile類中有個方法seek(long a),用來定位RandomAccessFile流的讀寫位置,參數a肯定讀寫位置距離文件開頭的字節數。還能夠調用getFilePointer()方 法獲取流當前讀寫位置。RandomAccessFile流對文件的讀寫比順序讀寫更爲靈活!
(該類還有許多方法,詳細查看JDK)
數據流:(DataInputStream和DataOutputStream類)
數據輸入流和數據輸出流,容許程序按照與機器無關的風格讀取Java原始數據。也就是說,當讀取一個數值時,沒必要關心這個數值應該是多少字節。
構造方法:
DataInputStream(InputStream in) //將建立的數據輸入流指向一個由in指定的底層輸入流
DataInputStream(OutputStream out) //將建立的數據輸出流指向一個由out指定的底層輸出流
(這個流類很神奇!Java確實提供了不少C++程序員很渴望的高級工具,詳細查看JDK吧)
帶進度條的輸入流:
使用javax.swing.ProgressMonitorInputStream類建立的輸入流讀取文件時能夠看見文件的讀取進度。
構造方法以下:
ProgressMonitorInputStream(Component c, Object message, InputStream in) //進度條在c指定組件正前方顯示,若取null,則在屏幕正前方顯示,message指定在進度條上的顯示信息(String)
示例以下:
import javax.swing.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
public class test1 {
public static void main(String[] args) {
byte b[] = new byte[2];
JTextArea text = new JTextArea(20,20);
JFrame jframe = new JFrame();
jframe.setSize(280,300);
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.add(new JScrollPane(text),BorderLayout.CENTER);
jframe.validate();
try{
FileInputStream input = new FileInputStream("test1.java");
ProgressMonitorInputStream input_progress = new ProgressMonitorInputStream(jframe,"讀取java文件",input);
ProgressMonitor p = input_progress.getProgressMonitor();
while(input_progress.read(b) != 1){
String s = new String(b);
text.append(s);
Thread.sleep(10);
}
}
catch(Exception e){}
}
}
對象流:(ObjectInputStream和ObjectOutputSteam類)
ObjectInputStream(對象輸入流)和ObjectOutputSteam(對象輸出流)類分別是InputStream和OutputStream類的子類。
ObjectInputStream對象調用readObject()方法讀取一個對象到程序中,ObjectOutputStream對象調用writerObject(Object obj)方法將一個對象obj寫入到一個文件。
兩個類構造方法以下:
ObjectInputStream(InputStream in) //in爲InputStream的子類建立的輸入流對象
ObjectOutputSteam(OutputStream out) //out爲OutputStream的子類建立的輸出流對象
使用對象流時,要保證對象是序列化的。這是爲了保證能把對象寫入文件並能正確讀回到程序的緣故。
一個類實現了Serializable 接口,它建立的對象就是序列化的。(Serializable接口中的方法對程序不可見,由JVM自動實現,所以實現該接口不須要實現額外的方法。但要注 意,使用對象流把一個對象寫入到文件時,除了要保證對象是序列化的,還要保證對象的成員對象也必須是序列化的。)
示例:
import java.io.*;
public class Student implements Serializable {
String name = null;
double height;
public Student(String name, double height) {
// TODO 自動生成構造函數存根
this.name = name;
this.height = height;
}
public void setHeight(double c){
this.height = c;
}
}
public class test1 {
public static void main(String[] args) {
Student zhang = new Student("張三", 1.65);
try{
FileOutputStream file_out = new FileOutputStream("s.txt");
ObjectOutputStream object_out = new ObjectOutputStream(file_out);
object_out.writeObject(zhang);
FileInputStream file_in = new FileInputStream("s.txt");
ObjectInputStream object_in = new ObjectInputStream(file_in);
Student li = (Student)object_in.readObject();
li.setHeight(1.78);
li.name = "李四";
System.out.println(zhang.name+"身高是:"+zhang.height);
System.out.println(li.name+"身高是:"+li.height);
}
catch(ClassNotFoundException event){
System.out.println("不能讀出對象");
}
catch(IOException event){
System.out.println("can not read file "+event);
}
}
}
序列化與對象克隆:
一個類的兩個對象若是具備相同引用,那麼他們具備相同的實體和功能。如:
A one = new A();
A two = one;
這樣對one成員變量的操做將會改變two中的成員變量(兩個實體是同一個)。
若是想獲得對象的克隆對象(克隆對象的變化不會引發原對象的變化),調用clone()方法便可。(注意:若是源對象有引用型成員變量,就牽涉到深度克隆問題,這時要重寫clone()方法,相似於C++中的深淺拷貝。)
使用對象流很容易獲取一個序列化對象的克隆。(由於將對象寫入對象輸出流指向的目的地再讀回的對象必定是原對象的一個克隆)
專門寫一個利用對象輸入輸出流克隆對象的類:
import java.io.*;
public class GetCloneObject {
public Object getClone(Object obj){
Object object = null;
try{
FileOutputStream file_out = new FileOutputStream("對象的序列化信息.txt");
ObjectOutputStream object_out = new ObjectOutputStream(file_out);
object_out.writeObject(obj);
FileInputStream file_in = new FileInputStream("對象的序列化信息.txt");
ObjectInputStream object_in = new ObjectInputStream(file_in);
object = object_in.readObject();
}
catch(Exception event){
System.out.println(event);
}
return object;
}
}
Java提供的絕大多數對象都是序列化的。如StringBuffer,Component類等,它們都實現了Serializable接口。能夠把組件寫入輸出流,而後再用輸入流讀取該組件的克隆。
以下示例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyWin extends JFrame implements ActionListener {
JTextArea text = null;
JButton button;
GetCloneObject cloneObject;
public MyWin(){
// TODO 自動生成構造函數存根
setLayout(new FlowLayout());
cloneObject = new GetCloneObject();
text = new JTextArea(6,10);
button = new JButton("獲得文本區的克隆");
button.addActionListener(this);
setVisible(true);
add(new JScrollPane(text));
add(button);
setSize(580,300);
validate();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
// TODO 自動生成方法存根
JTextArea textClone = (JTextArea)cloneObject.getClone(text);
textClone.setBackground(Color.pink);
this.add(new JScrollPane(textClone));
this.validate();
}
}
public class test1 {
public static void main(String[] args) {
MyWin win = new MyWin();
}
}
文件鎖:(FileLock和FileChannel類) java.nio.FileLock和java.nio.channels.FileChannel類。輸入,輸出流讀寫文件時能夠用文件鎖,用RandomAccessFile類建立的流在讀寫文件時可使用文件鎖,只要不解除該鎖,其餘線程沒法操做被鎖定的文件。 (1)、先用RandomAccessFile流創建指向文件的流對象(讀寫屬性必須是rw): RandomAccessFile input = new RandomAccessFile("hello.java","rw"); (2)、流對象input調用方法getChannel()得到一個鏈接到底層文件的FileChannel對象(信道): FileChannel channel = input.getChannel(); (3)、信道調用tryLock()或lock()方法得到一個FileLock(文件鎖)對象,這個過程叫作對文件加鎖: FileLock lock = channel.tryLock(); 文件鎖對象產生後,禁止任何程序對文件進行操做或再進行加鎖。若是想進行操做必須先讓FileLock對象調用release()方法釋放文件鎖: lock.release();