在core java上就把IO分成了 流和文件 這兩個最最基本和最根源的類型
流就是對字節的操作 文件就是對文件和目錄的操作
也就是說 File是在文件系統裏 在不打開文件的情況下的操作 流是對文件的內容的操作
基礎 & File類
tips
' File可以是任何文件或者是文件夾
' java 是用 "/“ 來做結合字母做轉義字符 因此路徑要用 "//" 來分隔 File f=new File("e://**//******")
' File類有常量 separator來表示分隔符 在linux下爲 "/" 在win下爲"/" 這個separator是string類型的
還有一個 separatorChar是char類型的
' File.separator 表示了當前的根目錄
' File(File parent, String child)
根據 parent 抽象路徑名和 child 路徑名字符串創建一個新 File
實例。
Stirng str="one"+File.separator+"two.txt";
File f=new File(dir, str);
f.createNewFile();
' 刪除方法 delete() deleteOnExit()是在程序終止的時候刪除文件
' createTempFile 是在缺省的temp目錄下創建 臨時文件 並賦值 構造的時候可指定前綴名和後綴名
' list() 返回目錄內的文件和文件夾名稱的 String[]
' FileNameFilter() 文件名過濾器接口 裏面有accept方法 File的list()有能力來callback 它
String的 indexOf(string s)方法 返回此字符串的索引 如果沒有返回 -1
因此 過濾文件名的時候可以這麼寫
String s = "lessons" + File.separator + "ssdf" + File.separator + "09";
File f = new File(fdir,s);
String[] names = f.list(new FilenameFilter()...{
public boolean accept(File dir, String name)...{
return name.indexOf(".java") != -1;
}
});
for(int j = 0; j < names.length; j++)
System.out.println(names[j]);
也可以像TIJ 上那樣寫的 再寫個實現了FilenamFilter的類 作爲list()的參數
eg:對文件夾的操作 列出所有文件
FileTest.java
class FileTest...{
public static void main(String[] args) throws Exception
...{
/**//*
//File f = new File("1.txt");
//f.createNewFile();
//f.mkdir(); //創建文件夾
//file的另一種方法,指定路徑
//File f = new File("E:/lessons/sunxin/09/1.txt"); /注意用雙反斜槓
//f.createNewFile();
File f = new File(File.separator);//創建文件分割符,代表當前的目錄所在的盤符
String s = "lessons" + File.separator + "sunxin" + File.separator + "09" +File.separator+"1.txt";
//路徑的設置 是一個string類型的(中間注意要加上分割符)
//file的另一個構造方法
File f2 = new File(f, s);//在當前目錄下創建
f2.createNewFile();
//f2.delete();
f2.deleteOnExit(); //在程序退出的時候刪除文件
Thread.sleep(13000);
*/
File fdir = new File(File.separator);
String s = "test" + File.separator +"lessons" + File.separator + "sunxin" + File.separator + "09";
File f = new File(fdir,s);
//利用list方法返回的是string類的數組,但是filenamefilter是一個接口
//用匿名類
String[] names = f.list(new FilenameFilter()...{
public boolean accept(File dir, String name)...{
return name.indexOf(".java") != -1;
}
});
for(int j = 0; j < names.length; j++)
System.out.println(names[j]);
}
}
流類
流類用不同的分法可以分爲不同的類
可分爲 輸入流和輸出流
可分爲 節點流和過濾流 管道流
還可以分爲 字節流和字符流
最重要和最基礎的類和方法
OutputStream 所有輸出流&字節流的超類
提供最基本的輸出方法write()和刷新輸出流的方法flush() 關閉方法close()
InputStream 所有輸入流&字節流的超類
提供一些基本的讀入方法 read() 重定位reset()等等方法
在lang包裏有一個經常用到的System裏提供了兩個標準的輸入和輸出流in和out分別是InputStream和PrintStream
一個例子 在cmd裏等待輸入 並在回車後打印出來
public class Test
...{
public static void main(String[] args)throws Exception
...{
int h;
while((h=System.in.read())!=-1)
...{
System.out.write(h);
}
}
}
write(int b)
將指定的字節寫入此輸出流。write
的常規協定是:向輸出流寫入一個字節。要寫入的字節是參數 b
的八個低位。b
的 24 個高位將被忽略。
read()
從輸入流讀取下一個數據字節。返回 0
到 255
範圍內的 int
字節值。如果因已到達流末尾而沒有可用的字節,則返回值 -1
。在輸入數據可用、檢測到流的末尾或者拋出異常前,此方法一直阻塞。
這個程序在運行的時候是這樣的
在命令行裏輸入的字符read方法會得到字符的默認編碼下的int
比如輸入一個w 會得到一個01110111 也就是一個字節的十六進制的77 十進制的119 然後在write的時候將這個int的低8位寫入一個字節 因爲使用的是PrintStream的write 所以將會使用系統默認的字符集轉換並輸出字符
再比如輸入的是一個 "王" 得到的是 205 245 也就是二進制的 11001101 11110101 然後用字符集轉換輸出
我機器的系統默認字符集使用的是GBK 所以在輸出的時候沒有發生亂碼
分類中按節點流 過濾流來分比較好 其他的類型都比較好理解
在OutputStream中 有很多子類
其中FilterOutputStream及其子類都是是過濾流
其他的FileOutputStream 等是節點流 PipedOutputStream是管道流(用於線程間的通信)
FileOutputStream是對文件的流的寫操作
分別舉例 創建文本文件並寫入數據
class StreamTest...{
public static void main(String[] args) throws Exception...{
FileOutputStream f1 = new FileOutputStream("1.rmvb");
f1.write("http://www.rainytooo.com".getBytes());
f1.close();
}
}
用文本編輯器打開可以看到字符串
再看看幾個過濾流的作用
class StreamTest...{
public static void main(String[] args) throws Exception...{
FileOutputStream f1 = new FileOutputStream("1.rmvb");
BufferedOutputStream bf = new BufferedOutputStream(f1);
bf.write("http://www.rainytooo.com".getBytes());
bf.flush();
bf.close();
}
}
BufferOutputStream是過濾流中的一種 用於將字節寫到緩衝先 等緩衝區滿纔會寫入到文件中
DataOutputStream將不同的java數據類型寫入到流中 都轉換成byte 並且從最高位開始寫
class StreamTest...{
public static void main(String[] args) throws Exception...{
FileOutputStream f1 = new FileOutputStream("1.rmvb");
BufferedOutputStream bf = new BufferedOutputStream(f1);
DataOutputStream df = new DataOutputStream(bf);
byte a1 = 1;
char a2 = 'a';
float a3 = 1.3f;
int a4 = 1;
df.writeByte(a1);
df.writeChar(a2);
df.writeFloat(a3);
df.writeInt(a4);
df.close();
}
}
這些數據都被換成了相應的字節數據
1 byte 1個字節 對應 01
a char 2 個字節 對應 00 61
1.3f float 4個字節 對應 3F A6 66 66
1 int 4個字節 對應 00 00 00 01
這個過濾的作用就很明顯了
可以自己根據需要不斷重組過濾流類來得到自己想要的功能的過濾流類 只要一個過濾流的構造以另一個過濾流爲參數
打印流PrintStream
System裏的out 就是一個打印流 有各種格式化的輸出
另一個例子用來說明管道流的作用
class Producer extends Thread...{
private PipedOutputStream pos;
public Producer(PipedOutputStream pos)...{
this.pos=pos;
}
public void run()...{
try
...{
pos.write("Hello,RainyTooo!".getBytes());
pos.close();
}catch(Exception e)
...{
e.printStackTrace();
}
}
}
class Consumer extends Thread...{
private PipedInputStream pis;
public Consumer(PipedInputStream pis)...{
this.pis=pis;
}
public void run()...{
try
...{
byte[] byt = new byte[100];
int len = pis.read(byt);
System.out.println(new String(byt,0,len));
pis.close();
}catch(Exception e)
...{
e.printStackTrace();
}
}
}
public class PipedStreamTest...{
public static void main(String[] args)...{
PipedOutputStream pos = new PipedOutputStream(); //創建尚未連接到傳送輸入流的傳送輸出流
PipedInputStream pis = new PipedInputStream();
try
...{
pos.connect(pis); //用管道的輸出留連接輸入流;
new Producer(pos).start(); //啓動線程;
new Consumer(pis).start();
}catch(Exception e)
...{
e.printStackTrace();
}
}
}
管道流之間誰連接誰都可以的
ByteArrayOutputStream是一個把字節數組當作輸出流的實現 具有緩衝區 可以在構造額達時候自己設定 其中有方便的方法得到字符串和輸出到文件
主要有以下三個方便的方法
byte[] |
toByteArray() 創建一個新分配的字節數組。 |
String |
toString() 將緩衝區的內容轉換爲字符串,根據平臺的默認字符編碼將字節轉換成字符。 |
toString方法還有重載的
void |
writeTo(OutputStream out) 將此字節數組輸出流的全部內容寫入到指定的輸出流參數中,這與使用 out.write(buf, 0, count) 調用該輸出流的 write 方法效果一樣。 |
一個例子
public class ByteArrayTest
...{
public static void main(String[] args)throws Exception
...{
ByteArrayOutputStream bos=new ByteArrayOutputStream();
String s="This is a test";
byte[] buf=s.getBytes();
bos.write(buf);
System.out.println(bos.toString());
byte[] buf2= bos.toByteArray();
for (int i=0; i<buf.length; i++)
...{
System.out.print((char) buf2[i]);
}
FileOutputStream f=new FileOutputStream("testByteArray.txt");
bos.writeTo(f);
}
}
SequenceInputStream(順序輸入流)
import java.util.*;
class InputStreamEnumerator implements Enumeration
...{
private Enumeration files;
public InputStreamEnumerator(Vector files)
...{
this.files = files.elements();
}
public boolean hasMoreElements()
...{
return files.hasMoreElements();
}
public Object nextElement()
...{
try
...{
return new FileInputStream(files.nextElement().toString());
} catch (Exception e) ...{
return null;
}
}
}
class SequenceInputStreamDemo
...{
public static void main(String args[]) throws Exception
...{
int c;
Vector files = new Vector();
files.addElement("StreamTest.java");
files.addElement("Test.java");
InputStreamEnumerator e = new InputStreamEnumerator(files);
InputStream input = new SequenceInputStream(e);
while ((c = input.read()) != -1)
...{
System.out.print((char) c);
}
input.close();
}
}
字符流
Reader和Write
兩個抽象類 作用就是方便字符的 輸入和輸出 子類必須實現read和close方法
Reader的子類
BufferedReader CharArrayReader FilterReader InputStreamReader PipedReader StringReader
Writer的子類
BufferedWriter CharArrayWriter FilterWriter OutputStreamWriter PipedWriter StringWriter PrintWriter
其中InputStreamReader 的子類FileReader 和 OutputStreamWriter的 子類 FileWriter提供了對文件的直接操作字符的方式
RandomAccessFile(隨機訪問文件類)
RandomAccessFile
它是一個完全獨立的class,擁有大量的原生函數,它和其他的IO有本質上的差異
,允許你在文件內自由的前後移動seek()的作用是指針
public RandomAccessFile(File file,
String mode)
throws FileNotFoundException創建從中讀取和向其中寫入(可選)的隨機存取文件流,該文件由 File 參數指定。將創建一個新的 FileDescriptor 對象來表示此文件的連接。
mode 參數指定用以打開文件的訪問模式。允許的值及其含意爲:
值
含意
"r" 以只讀方式打開。調用結果對象的任何 write 方法都將導致拋出 IOException。
"rw" 打開以便讀取和寫入。如果該文件尚不存在,則嘗試創建該文件。
"rws" 打開以便讀取和寫入,對於 "rw",還要求對文件的內容或元數據的每個更新都同步寫入到基礎存儲設備。
"rwd" 打開以便讀取和寫入,對於 "rw",還要求對文件內容的每個更新都同步寫入到基礎存儲設備。
有3種string的寫入方法
writeByte(String s)沒有讀取的方法
writeChar(String s)
writeUTF(String s)可以記錄字節的長度在前面用兩個字節表示
在RandomAccessFile中
long getFilePointer()
返回此文件中的當前偏移量。
例子 :用RandomAccessFile類讀寫文件
public class RandomAccessFileTest
...{
public static void main(String[] args)throws Exception
...{
Student a1 = new Student(1,"wang",99.0);
Student a2 = new Student(2,"zhang",22.0);
Student a3 = new Student(3,"xiang",33.0);
RandomAccessFile raf = new RandomAccessFile("students.txt", "rw");
a1.writeStudents(raf);
a2.writeStudents(raf);
a3.writeStudents(raf);
Student s = new Student();
raf.seek(0); //將文件指針移到啓始位置;
for(long i =0; i<raf.length();i=raf.getFilePointer()) //返回long型的指針偏移量
...{
s.readStudents(raf);
System.out.println(s.num+": " + s.name+": " +s.scores);
}
raf.close();
}
}
class Student
...{
int num;
String name;
double scores;
public Student()...{
}
public Student(int num, String name, double scores)...{
this.num=num;
this.name=name;
this.scores=scores;
}
public void writeStudents(RandomAccessFile raf)throws IOException
...{
raf.writeInt(num);
raf.writeUTF(name);
raf.writeDouble(scores);
}
public void readStudents(RandomAccessFile raf)throws IOException
...{
num = raf.readInt();
name = raf.readUTF();
scores = raf.readDouble();
}
}
以便保存和還原一個對象
對象序列化必須實現Serializable或者Externalizable接口
1 當一個對象序列化的時候只保存非靜態的成員變量不能保存任何成員方法和靜態的成員變量
2 如果一個對象的成員變量是一個對象,那麼這個對象的數據也會被保存
3 如果一個可序列化的對象包含一個不可序列化的對象的引用,那麼整個序列化的操作就將失敗
聲明爲transient時可以繼續序列化
class ObjectSerialTest
...{
public static void main(String[] args) throws Exception
...{
Employee e1=new Employee("zhangsan",25,3000.50);
Employee e2=new Employee("lisi",24,3200.40);
Employee e3=new Employee("wangwu",27,3800.55);
FileOutputStream fos=new FileOutputStream("employee.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(e1);
oos.writeObject(e2);
oos.writeObject(e3);
oos.close();
FileInputStream fis=new FileInputStream("employee.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
Employee e;
for(int i=0;i<3;i++)
...{
e=(Employee)ois.readObject();
System.out.println(e.name+":"+e.age+":"+e.salary);
}
ois.close();
}
}
class Employee implements Serializable
...{
String name;
int age;
double salary;
transient Thread t=new Thread();
public Employee(String name,int age,double salary)
...{
this.name=name;
this.age=age;
this.salary=salary;
}
private void writeObject(java.io.ObjectOutputStream oos) throws IOException
...{
oos.writeInt(age);
oos.writeUTF(name);
System.out.println("Write Object");
}
private void readObject(java.io.ObjectInputStream ois) throws IOException
...{
age=ois.readInt();
name=ois.readUTF();
System.out.println("Read Object");
}
}