java的IO複習

複習一下 TIJ 做一下IO的筆記 把以前的筆記轉到Blog上

在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 實例。

    File dir=new File(File.separator);
    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

    因此 過濾文件名的時候可以這麼寫

        File fdir = new File(File.separator);
        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

import java.io.*;

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裏等待輸入 並在回車後打印出來

import java.io.*;

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()

從輸入流讀取下一個數據字節。返回 0255 範圍內的 int 字節值。如果因已到達流末尾而沒有可用的字節,則返回值 -1。在輸入數據可用、檢測到流的末尾或者拋出異常前,此方法一直阻塞。

這個程序在運行的時候是這樣的

在命令行裏輸入的字符read方法會得到字符的默認編碼下的int

比如輸入一個w 會得到一個01110111 也就是一個字節的十六進制的77  十進制的119 然後在write的時候將這個int的低8位寫入一個字節  因爲使用的是PrintStream的write 所以將會使用系統默認的字符集轉換並輸出字符

再比如輸入的是一個 "王" 得到的是 205 245 也就是二進制的 11001101 11110101 然後用字符集轉換輸出

我機器的系統默認字符集使用的是GBK 所以在輸出的時候沒有發生亂碼

 

 分類中按節點流 過濾流來分比較好 其他的類型都比較好理解

OutputStream中 有很多子類

其中FilterOutputStream及其子類都是是過濾流

其他的FileOutputStream  等是節點流 PipedOutputStream是管道流(用於線程間的通信)

FileOutputStream是對文件的流的寫操作

分別舉例 創建文本文件並寫入數據

import java.io.*;

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();
               
                                        
        }

}

用文本編輯器打開可以看到字符串

再看看幾個過濾流的作用

import java.io.*;

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 並且從最高位開始寫

import java.io.*;

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 就是一個打印流 有各種格式化的輸出

 

另一個例子用來說明管道流的作用

import java.io.*;

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 方法效果一樣。

一個例子

import java.io.*;

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(順序輸入流)

SequenceInputStream類允許連接多個InputStream流。SequenceInputStream的構造不同於任何其他的InputStream。SequenceInputStream構造函數要麼使用一對InputStream,要麼用InputStream的一個Enumeration,顯示如下:
SequenceInputStream(InputStream first, InputStream second)
SequenceInputStream(Enumeration streamEnum)
操作上來說,該類滿足讀取完第一個InputStream後轉去讀取第二個流的讀取要求。使用Enumeration的情況下,它將繼續讀取所有InputStream流直到最後一個被讀完。
 
例子
輸出兩個文件內容
import java.io.*;
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();
    }

}

字符流

ReaderWrite

兩個抽象類   作用就是方便字符的 輸入和輸出 子類必須實現read和close方法

Reader的子類

BufferedReader   CharArrayReader FilterReader InputStreamReader PipedReader  StringReader

Writer的子類

BufferedWriter   CharArrayWriter FilterWriter OutputStreamWriter PipedWriter  StringWriter  PrintWriter

其中InputStreamReader 的子類FileReader 和 OutputStreamWriter的 子類 FileWriter提供了對文件的直接操作字符的方式

RandomAccessFile(隨機訪問文件類)

RandomAccessFile 包裝了一個隨機訪問的文件。它不是派生於InputStream 和OutputStream,而是實現定義了基本輸入/輸出方法的DataInput和DataOutput接口。 這個類同時具有讀和寫的方法   還有文件指針可以方便在制定位置讀和寫操作
提供了文件的隨機存取的功能整合
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類讀寫文件
import java.io.*;

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時可以繼續序列化
例子:
import java.io.*;

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");
        }


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章