Java中IO總結(jié)

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ù)雜度。

如圖所示:

QQ截圖20170729150115.jpg

字節(jié)流

流序列中的數(shù)據(jù)既可以是未經(jīng)加工的原始二進(jìn)制數(shù)據(jù),也可以是經(jīng)一定編碼處理后符合某種格式規(guī)定的特定數(shù)據(jù)。因此Java中的流分為兩種:

  1. 字節(jié)流:數(shù)據(jù)流中最小的數(shù)據(jù)單元是字節(jié)
  2. 字符流:數(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)閉.

主要的子類(截圖):

io2.jpg
  • 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)資源。

主要的子類(截圖):

IO3.jpg
    1. ByteArrayOutputStream:把信息存入內(nèi)存中的一個(gè)緩沖區(qū)中
    1. FileOutputStream:把信息存入文件中
    1. PipedOutputStream:實(shí)現(xiàn)了pipe的概念,主要在線程中使用
    1. SequenceOutputStream:把多個(gè)OutStream合并為一個(gè)OutStream
      流結(jié)束的判斷:方法read()的返回值為-1時(shí);readLine()的返回值為null時(shí)。

緩沖輸入輸出流 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+"]";
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容