IO
IO(Input/Output)是計算機輸入/輸出的接口。java的核心庫java.io提供了全方面的IO接口,包括:檔案系統的操作,檔案讀寫,标準裝置輸出等等
File類及使用
File對象封裝了檔案或路徑屬性,但不包含對檔案讀寫資料的方法
部分File類常用方法
public String getName() 擷取檔案或目錄的名字
public String getParent() 擷取父目錄的路徑字元串
public File getParentFile() 擷取父目錄路徑的File對象
public String getAbsolutePath() 擷取檔案或目錄的絕對路徑
public boolean exists() 判斷檔案或目錄是否存在
Public File[] listFiles() 獲得目錄裡的檔案和目錄封裝成File對象放到File數組裡
public boolean isDirectory() 判斷是不是檔案夾或者目錄
public boolean isFile() 判斷是不是檔案
public long length() 擷取檔案的大小
boolean delete() 删除檔案或檔案夾
boolean mkdir() 建立檔案夾
package my;
import java.io.*;
public class IO {
public static void main(String[] args)
{
File file1 = new File("c:\\test");
System.out.println(file1.getAbsolutePath());
System.out.println(file1.getParent()); //test的父目錄
System.out.println(file1.isDirectory()); //是否存在test檔案夾
System.out.println(file1.isFile()); //是否存在test檔案
System.out.println(file1.exists()); //是否存在
System.out.println(file1.length());
System.out.println(file1.delete());//存在直接删除test檔案夾
//隻能删除空檔案夾,若裡面有檔案則需要遞歸删除
File file2 = new File("c:\\apple");
System.out.println("apple " + file2.mkdir());
//建立成功傳回true,若原來有此檔案夾則傳回false
File file3 = new File("c:\\apple\\1.txt");
try {
System.out.println("1.txt " + file3.createNewFile());
//建立檔案,成功true,原來有傳回false
//使用creatNewFile的時候會抛出異常,需要捕獲
}
catch(IOException e){
e.printStackTrace();
}
String[] files1 = file2.list();
for(String f:files1) {
System.out.println("files1 " + f);
}
//擷取一個檔案裡面的所有檔案名和目錄名
//傳回一個字元串數組,這些字元串指定此抽象路徑名表示的目錄中的檔案和目錄
String[] files2 = file2.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
//dir : 被找到的檔案所在的目錄
//name:檔案的名稱
return name.endsWith(".txt");
}
});
for(String f:files2) {
System.out.println("files2 " + f);
}
//傳回檔案裡面指定值的檔案名和目錄名
//傳回一個字元串數組,這些字元串指定此抽象路徑名表示的目錄中的檔案和目錄
File[] files3 = file2.listFiles();
for(File f:files3) {
System.out.println("files3 " + f.getName() + "--" + f.length());
}
//傳回一個抽象路徑名數組,這些路徑名表示此抽象路徑名表示的目錄中的檔案
//包括一些檔案屬性:檔案大小等
File[] files4 = file2.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
});
for(File f:files4) {
System.out.println("files4 " + f.getName() + "--" + f.length());
}
//傳回一個抽象路徑名數組,這些路徑名表示此抽象路徑名滿足指定過濾器的檔案和目錄
//包括一些檔案屬性:檔案大小等
File[] files5 = file2.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".txt");
}
});
for(File f:files5) {
System.out.println("files5: " + f.getName() + "--" + f.length());
}
//傳回一個抽象路徑名數組,這些路徑名表示此抽象路徑名滿足指定過濾器的檔案和目錄
//包括一些檔案屬性:檔案大小等
}
}
Console:
//c:\test
//c:\
//false
//false
//false
//0
//false
//apple false
//1.txt false
//files1 1.doc
//files1 1.mpp
//files1 1.txt
//files1 2.txt
//files2 1.txt
//files2 2.txt
//files3 1.doc--9216
//files3 1.mpp--178688
//files3 1.txt--0
//files3 2.txt--0
//files4 1.txt--0
//files4 2.txt--0
//files5: 1.txt--0
//files5: 2.txt--0
FileInputStream和FileOutputStream
FileInputStream類和FileOutputStream類用于從檔案讀取/寫入位元組,他們所有的方法都是從InputTream類和OutputStream類中繼承的,沒有引進新方法
I/O類中幾乎所有的方法都會抛出異常IOExecption,是以必須在方法中聲明抛出IOException異常,或者将代碼放到tyr-catch塊這種
對檔案的讀寫操作使用緩沖區會大大提高檔案讀寫效率
FileInputStream能從檔案讀取位元組的InputStream類
FileOutputStream表示能向檔案寫入位元組的OutputStream類
package my;
import java.io.*;
public class FileInputStreamOutputStream {
public static void main(String[] args) {
try {
FileCopyUtil.copyFile(new File("c:\\picture\\1.png"), new File("c:\\test\\1.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class FileCopyUtil{
public static void copyFile(File src, File dst) throws IOException{
FileInputStream fis = new FileInputStream(src); //從原檔案讀取檔案
FileOutputStream fos = new FileOutputStream(dst); //寫到指定檔案當中
//直接從輸入流中讀到輸出流中
long time1 = System.currentTimeMillis();
int data = -1;
while((data = fis.read()) != -1){
fos.write(data);
}
fis.close();
fos.close();
long time2 = System.currentTimeMillis();
//将輸入流中的資料存到緩沖區中最後一起讀到輸出流
byte [] buf = new byte[1024*1024];//建立一個1M大小的緩沖區,用來存放輸入流中的位元組數
int len = 0;
long time1 = System.currentTimeMillis();
while((fis.read(buf)) != -1) {
fos.write(buf,0,len);
}
fis.close();
fos.close();
long time2 = System.currentTimeMillis();
System.out.println("finished : " + (time2 - time1));
}
}
ByteArrayInput/OutputStream
ByteArrayInputStream是把位元組數組當成源的輸入流
ByteArrayOutputStream是把位元組數組當做目标的輸出流
package my;
import java.io.*;
public class ByteArrayInputStreamByteArrayOutputStream {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//把字元串轉換成位元組數組,再從這個位元組數組裡讀出來一個個列印輸出
String str = "hello,world";
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
int data = -1;
while((data = bis.read()) != -1) {
System.out.print((char)data);
}
bis.close();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(97);
bos.write(65);
bos.write("hello".getBytes());
byte[] buff = bos.toByteArray();
for(byte data : buff) {
System.out.print((char)data);
}
FileOutputStream fos = new FileOutputStream("c:\\test\\1.txt", true);
//隻會追加不會覆寫源檔案内容
bos.writeTo(fos);
//把ByteArrayOutputStream内部緩沖區的資料寫到對應的檔案輸出流中
fos.close();
}
}
FilterInputStream和FilterOutputStream(過濾流)
是為某種目的過濾位元組的資料流,基本位元組輸入流提供的讀取方法隻能用來讀取位元組,如果要讀取整數值、雙精度值或字元串,需要一個過濾器類來包裝位元組輸入流
常用的過濾流 BufferedInputStream和BufferedOutputStream, DataInputStream和DataOutputStream
DataInputStream從資料流中讀取位元組并轉化為适當的基本類型值或字元串,DataOutputStream将基本類型的值或字元串轉化為位元組,并輸出到輸出資料流
BufferedInputStream和BufferedOutputStream可以通過減少讀寫次數來提高輸入輸出速度,BufferedOutputStream類為存儲位元組在流中添加一個緩沖區,以提高處理效率
BufferedInputStream類和BufferedOutputStream類
import java.io.*;
public class BufferedInputStreamOutputStream {
public static void main(String[] args) {
try {
FileUtil.copyFile(new File("c:\\picture\\1.png"), new File("c:\\test\\1.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class FileUtil{
public static void copyFile(File src, File dst) throws IOException{
FileInputStream fis = new FileInputStream(src); //從原檔案讀取檔案
FileOutputStream fos = new FileOutputStream(dst); //寫到指定檔案當中
BufferedInputStream bis = new BufferedInputStream(fis);
//對fis這個檔案增加緩沖區的功能
BufferedOutputStream bos = new BufferedOutputStream(fos);
int data = 0;
long time1 = System.currentTimeMillis();
while((data = bis.read()) != -1) {
bos.write(data);
}
//關閉包裝類就可以
bis.close();
bos.close();
long time2 = System.currentTimeMillis();
System.out.println("finished : " + (time2 - time1) + "毫秒");
}
}
DataInputStream類和DataOuputStream類
package my;
import java.io.*;
public class DataInputStreamOutputStream {
public static void main(String[] args) throws IOException {
String name = "zhangsan";
int age = 10;
boolean flag = true;
char sex = 'm';
double money = 100.2;
//寫入檔案操作
DataOutputStream dos = new DataOutputStream(new FileOutputStream("c:\\test\\b.txt"));
//建立一個檔案并将它執行個體化
dos.writeUTF(name);
dos.writeInt(age);
dos.writeBoolean(flag);
dos.writeChar(sex);
dos.writeDouble(money);
dos.close(); //關閉檔案
//将檔案資訊讀取出來
DataInputStream dis = new DataInputStream(new FileInputStream("c:\\test\\b.txt"));
//讀的必須和寫的順序一緻
System.out.println(dis.readUTF());
System.out.println(dis.readInt());
System.out.println(dis.readBoolean());
System.out.println(dis.readChar());
System.out.println(dis.readDouble());
dis.close();
}
}
BufferedInputStream和BufferedOutputStream:需要使用已經存在的節點流來構造,提供帶緩沖的讀寫,提高了讀寫的效率
DataInputStream和DataOutputStream:資料輸入輸出流允許應用程式讀寫基本java資料類型。應用程式可以使用資料輸出流寫入稍後有資料輸入流讀取。讀寫順序要保持與一緻
裝飾模式
裝飾模式可以在不使用創造更多子類的情況下,将對象的功能加以擴充
裝飾模式中的角色有
抽象構件(Component)角色:給出一個抽象接口,以規範準備接受附加責任的對象
具體構件(ConcreteComponent)角色:定義一個将要接受附加責任的類
裝飾(Decorator)角色:持有一個構件(Component)對象的執行個體,并定義一個與抽象構件方法一緻的方法
具體裝飾(ConcreteDecorator)角色:負責給構件對象“貼上”附加的責任
Component為統一接口,也是裝飾類和被裝飾類的基本類型。
ConcreteComponent為具體實作類,也是被裝飾類,他本身是個具有一些功能的完整的類。
Decorator是裝飾類,實作了Component接口的同時還在内部維護了一個ConcreteComponent的執行個體,并可以通過構造函數初始化。而Decorator本身,通常采用預設實作,他的存在僅僅是一個聲明:我要生産出一些用于裝飾的子類了。而其子類才是賦有具體裝飾效果的裝飾産品類。
ConcreteDecorator是具體的裝飾産品類,每一種裝飾産品都具有特定的裝飾效果。可以通過構造器聲明裝飾哪種類型的ConcreteComponent,進而對其進行裝飾
public interface Component { //接口
public void doThingA();
}
public class Decorator implements Component {
private Component component = null;
public Decorator(Component component) {
this.component = component;
}
@Override
public void doThingA() {
// TODO Auto-generated method stub
component.doThingA();//調用被裝飾對象的方法
}
}
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
// TODO Auto-generated constructor stub
}
@Override
public void doThingA() {
// TODO Auto-generated method stub
super.doThingA();//調用被包裝類的方法
doThingB();
}
//擴充的功能
private void doThingB() {
System.out.println("do B thing");
}
}
public class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component component) {
super(component);
// TODO Auto-generated constructor stub
}
@Override
public void doThingA() {
// TODO Auto-generated method stub
super.doThingA();//調用被包裝類的方法
doThingC();
}
//擴充的功能
private void doThingC() {
System.out.println("do C thing");
}
}
public class Test {
public static void main(String[] args) {
ConcreteComponent component = new ConcreteComponent();
//component.doThingA();
ConcreteDecorator decorator1 = new ConcreteDecorator(component);
//decorator1.doThingA();
ConcreteDecorator2 decorator2 = new ConcreteDecorator2(decorator1);
decorator2.doThingA();
}
}
字元流
位元組流提供處理任何類型輸入/輸出操作的足夠功能,但不能直接操作Unicode字元,因而需要字元流
字元流層次結構額頂層是Reader和Writer抽象類
Reader是定義java的流式字元輸入模式的抽象類
Writer是定義流式字元輸出的抽象類,該類方法都傳回void值并在出錯條件下抛IOException
FileReader和FileWriter
FileReader類表示可以讀取檔案内容的Reader類
FileWriter表示可以寫檔案的Writer類
import java.io.*;
public class FileReaderWriter {
public static void main(String[] args) throws IOException {
//将一個檔案的字元讀取出來寫到另一個檔案裡去
FileReader fr = new FileReader("c:\\test\\1.txt");
FileWriter fw = new FileWriter("c:\\test\\4.txt");
char [] buff = new char[100];
int len = 0; //實際讀到的字元個數
while((len = fr.read(buff)) != -1) {
fw.write(buff, 0, len);
}
fr.close();
fw.close();
}
}
BufferedReader和BufferedWriter
BufferedReader通過緩沖輸入提高性能
BufferedWriter通過緩沖輸出提高性能
其他流
ObjectInputStream/OutputStream
InputStreamReader/OutputStreamWriter
RandomAccessFile
ObjectInputStream/OutputStream
ObjectInputStream和ObjectOutputStream分别與FileOutputStream和FileInputStream一起使用時,可以為應用程式提供對對象的持久存儲。我們把對象以某種特定的編碼格式寫入稱之為“序列化”。把寫入的編碼格式内容還原成對象稱之為“反序列化”
被序列化的對象必須實作Serializable接口
ObjectOutputStream将java對象的基本資料類型和圖形寫入OutputStream
writeObject(Object obj):将指定的對象寫入ObjectOutputStream
ObjectInputStream對以前使用ObjectOutputStream寫入的基本資料和對象進行反序列化
readObject():從ObjectInputStream讀取對象
package otherio;
import java.io.*;
public class ObjectInputOutStream {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
//向檔案裡輸入對象,序列化
Student stu = new Student("zhangsan", 30);
//FileOutputStream fos = new FileOutputStream("c:\\test\\10.txt");
//ObjectOutputStream oos = new ObjectOutputStream(fos);
//與上面的等價
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:\\test\\10.txt"));
oos.writeObject(stu);//把對象序列化到指定的檔案輸出流中
oos.close();//釋放資源
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:\\test\\10.txt"));
try {
Student stu = (Student)ois.readObject();
System.out.println(stu);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Student implements Serializable{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() { //覆寫原有類裡的toString方法
return "Student [name = " + name + ", age =" + age + "]";
}
}
eg:Student [name = zhangsan, age =30]
InputStreamReader/OutputStreamWriter
轉換流是指将位元組流與字元流之間的轉換
轉換流的出現友善了對檔案的讀寫, 它在字元流與位元組流之間架起了一座橋梁,使原本毫無關聯的兩種流操作能夠進行轉化,提高了程式的靈活性
位元組流中的資料都是字元時,轉成字元流操作更高效
如果使用非預設編碼儲存檔案或者讀取檔案時,需要用到轉換流,因為位元組流的重載構造方法中有指定編碼格式的參數,而FileReader與FileWriter是預設編碼的文本檔案
常見的編碼表
ASCII:美國标準資訊交換碼,用一個位元組的7位可以表示
ISO8859-1:拉丁碼表,歐洲碼,表示用一個位元組的8位表示
GB2312:中國的中文編碼表
GBK:中國的中文編碼表更新
Unicode:國際标準碼,融合了多種文字,所有文字都用兩個位元組來表示
UTF-8:最多用三個位元組來表示一個字元
InputStreamReader是位元組流通向字元流的橋梁
OutputSteamWriter是字元流通向位元組流的橋梁
package otherio;
import java.io.*;
public class InputStreamWriterReader {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
//寫入檔案操作
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c:\\test\\10a.txt"), "utf-8");
BufferedWriter bw = new BufferedWriter(osw);//加了緩沖區
bw.write("你好");
bw.close();
//從檔案讀取操作,運用緩沖區
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("c:\\test\\10a.txt"),"utf-8"));
String line = null;
while((line = br.readLine())!= null) {
System.out.println(line);
}
}
}
eg:你好
RandomAccesFile(随機通路檔案)
支援對随機通路檔案的讀取和寫入
随機通路檔案的行為類似存儲在檔案系統中的一個大型byte數組存在指向該隐含數組的光标或索引,稱為檔案指針
輸入操作從檔案指針開始讀取位元組,随着對位元組的讀取而遷移此檔案指針
如果随機通路檔案以讀取/寫入模式建立,則輸出操作也可用;輸出操作從檔案指針開始寫入位元組,随着對位元組的寫入而前移此檔案指針
寫入隐含數組末尾之後的輸出操作導緻該數組擴充
該檔案指針可以通過getFilePointer方法讀取,通過seek方法設定
package otherio;
import java.io.*;
import java.util.Scanner;
public class RandomAccessFileio {
public static void main(String[] args) throws IOException{
Person[] persons = {new Person("lisi",90), new Person("justin",24), new Person("zhangsan",18), new Person("wangwu", 39)};
//初始化對象
java.io.RandomAccessFile raf = new java.io.RandomAccessFile("c:\\test\\io.txt", "rw");
//寫入資料到RandomAccessFile對象中去
for(int i = 0; i < persons.length; i++) {
raf.writeChars(persons[i].getName());
raf.writeInt(persons[i].getAge());
}
//讀取指定位置上的的Person對象
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt(); //輸入一個數,取第num個人的姓名和年齡
//使用seek方法來操作存取位置,從第0個開始,是以要seek-1
raf.seek((num-1) * Person.size());
Person person = new Person();
person.setName(readName(raf));
person.setAge(raf.readInt());
System.out.println("姓名" + person.getName());
System.out.println("年齡" + person.getAge());
raf.close();
}
private static String readName(RandomAccessFile raf) throws IOException {
char[] name = new char[15];
for(int i = 0; i < name.length; i++) {
name[i] = raf.readChar();
}
return new String(name).replace('\u0000', ' ');
}
}
class Person{
private String name; //2個位元組,unicode編碼,将名字長度固定為15個字元
private int age; //4個位元組
//person一共有34個位元組
public Person() {
}
public Person(String name, int age) {
StringBuilder builder = null;
//動态字元串,Stringbuilder預設大小:傳進去字元串+16
if(name != null) {
builder = new StringBuilder(name); //傳過來名字不為空,就等于其名字
}else {
builder = new StringBuilder(15); //為空就等于15
}
builder.setLength(15);//設定固定長度為15個,空字元'\u0000'
this.name = builder.toString() ;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//每個對象所占的位元組數
public static int size() {
return 34;
}
}