讓你再也忘不了IO相關(guān)知識(shí)-Java IO圖文詳解

1 裝飾模式

Java中IO使用的是裝飾模式,裝飾模式在Android中很常見(jiàn),比如系統(tǒng)的Context。

裝飾模式的模型

  • Component:抽象構(gòu)建接口。
  • ConcreteComponent:具體的構(gòu)建對(duì)象,實(shí)現(xiàn)組件對(duì)象接口,通常就是被裝飾的原始對(duì)象。就對(duì)這個(gè)對(duì)象添加功能。
  • Decorator:所有裝飾器的抽象父類(lèi),需要定義 一個(gè)與組件接口一致的接口,內(nèi)部持有一個(gè)Component對(duì)象,就是持有一個(gè)被裝飾的對(duì)象。
  • ConreteDecoratorA/ConreteDecoratorB:實(shí)際的裝飾器對(duì)象,實(shí)現(xiàn)具體添加功能。

2 流式部分

2.1 I/O體系

IO流需要站在內(nèi)存的角度去理解:讀入寫(xiě)出

讀入:將文件從外部讀入內(nèi)存中。

寫(xiě)出:從內(nèi)存中生成一個(gè)文件。

2.2 字節(jié)流

BufferInputStream+FileInputStream

Buffer:緩存,作用是提升性能,原理是減少磁盤(pán)的磁頭操作次數(shù)。

只能讀寫(xiě)byte類(lèi)型的數(shù)據(jù)。

File file = new File("txt/BufferedStreamTest.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read();

BufferOutputStream+FileOutputStream

File file = new File("txt/BufferedStreamTest.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(byteArray[0]);
bos.write(byteArray, 1, byteArray.length - 1);
//flush()的作用是強(qiáng)制進(jìn)行一次IO,比如最后寫(xiě)出的數(shù)據(jù)不夠緩存指定的長(zhǎng)度,就需要強(qiáng)制的執(zhí)行一次IO
bos.flush();
bos.close();

完整示例:

package site.exciter.learn.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedStreamTest {
    private static final byte[] byteArray = {
            0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
            0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
    };

    public static void main(String[] args) {
        testBufferedInputStream();
//        testBufferedOutputStream();

    }

    private static void testBufferedInputStream() {
        try {
            File file = new File("txt/BufferedStreamTest.txt");
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);

            //讀取前10個(gè)字節(jié)并輸出在控制臺(tái)
            for (int i = 0; i < 10; i++) {
                if (bis.available() >= 0) {
                    System.out.println(byteToString((byte) bis.read()));
                }
            }

            //在此輸入流中標(biāo)記當(dāng)前的位置,對(duì)reset方法的后續(xù)調(diào)用會(huì)在最后標(biāo)記的位置重新定位此流,以便后續(xù)重新讀取相同的字節(jié)。
            bis.mark(2000);
            //跳過(guò)并從輸入流中丟棄10字節(jié)的數(shù)據(jù)。
            bis.skip(10);

            //跳10個(gè)字節(jié)之后讀取剩余的部分
            byte[] b = new byte[1024];
            int n1 = bis.read(b, 0, b.length);
            System.out.println("n1的值為:" + n1);
            printByteValue(b);

            //調(diào)用reset之后,再次讀取會(huì)從mark標(biāo)記的位置開(kāi)始,也就是從第10個(gè)字節(jié)開(kāi)始讀取。
            bis.reset();
            int n2 = bis.read(b, 0, b.length);
            System.out.println("n2的值為:" + n2);
            printByteValue(b);


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void testBufferedOutputStream() {
        try {
            File file = new File("txt/BufferedStreamTest.txt");
            FileOutputStream fos = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            bos.write(byteArray[0]);
            bos.write(byteArray, 1, byteArray.length - 1);
            bos.flush();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String byteToString(byte b) {
        byte[] bArray = ;
        return new String(bArray);
    }

    private static void printByteValue(byte[] buf) {
        for (byte b : buf) {
            if (b != 0) {
                System.out.println(byteToString(b) + " ");
            }
        }
    }
}

DataInputStream+BufferedInputStream+FileInputStream

可以讀寫(xiě)所有基本類(lèi)型的數(shù)據(jù)。

File file = new File("txt/DataStreamTest.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);

DataOutputStream+BufferedOutputStream+FileOutputStream

File file = new File("txt/DataStreamTest.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);

完整示例:

package site.exciter.learn.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataStreamTest {
    public static void main(String[] args) {
//        testDataInputStream();
        testDataOutputStream();
    }

    private static void testDataInputStream() {
        try {
            File file = new File("txt/DataStreamTest.txt");
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            DataInputStream dis = new DataInputStream(bis);

            System.out.println(Long.toHexString(dis.readLong()));
            System.out.println(dis.readBoolean());
            System.out.println(byteToString(dis.readByte()));
            System.out.println(charToString(dis.readChar()));
            System.out.println(shortToString(dis.readShort()));
            System.out.println(Integer.toHexString(dis.readInt()));
            System.out.println(Long.toHexString(dis.readLong()));
            System.out.println(dis.readUTF());
            System.out.println(Long.toHexString(dis.readLong()));

            dis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void testDataOutputStream() {
        try {
            File file = new File("txt/DataStreamTest.txt");
            FileOutputStream fos = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            DataOutputStream dos = new DataOutputStream(bos);

            dos.writeBoolean(true);
            dos.writeByte((byte) 0x41);
            dos.writeChar((char) 0x4243);
            dos.writeShort((short) 0x4445);
            dos.writeInt(0x12345678);
            dos.writeLong(0x987654321L);

            dos.writeUTF("abcdefg");
            dos.writeLong(0x23433L);

            dos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String byteToString(byte val) {
        return Integer.toHexString(val & 0xff);
    }

    private static String charToString(char val) {
        return Integer.toHexString(val);
    }

    private static String shortToString(short val) {
        return Integer.toHexString(val & 0xffff);
    }
}

ObjectInputStream+BufferedInputStream+FileInputStream

可以讀寫(xiě)對(duì)象,包含ObjectArrayList等。

FileInputStream fis = new FileInputStream(newFile("txt/Object.txt"));
BufferedInputStream bis = new BufferedInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(bis);

while (ois.available() != -1) {
    Object object = ois.readObject();
    Book book = (Book) object;
    System.out.println(book.toString());
}

ois.close();

ObjectOutputStream+BufferedOutputStream+FileOutputStream

FileOutputStream fos = new FileOutputStream("txt/Object.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);

for (int i = 0; i < 10; i++) {
    oos.writeObject(new Book("三國(guó)演義", 102.0f));
}

oos.close();

2.3 字符流

BufferedReader+InputStreamReader+FileInputStream

FileInputStream fis = new FileInputStream("txt/InputStreamWriterTest.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);

String str;
while ((str = br.readLine()) != null) {
    System.out.println(str);
}

BufferedWriter+OutputStreamWriter+FileOutputStream

File file = new File("txt/OutputStreamWriterTest.txt");
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);

bw.write("new bee");
bw.flush();
bw.close();

使用上述方式就可以讀寫(xiě)文件,但是過(guò)程過(guò)于繁瑣,可以使用FileReader/FileWriter來(lái)簡(jiǎn)化流程。

BufferedReader+FileReader/BufferedWriter+FileWriter

File srcFile = new File("txt/BufferedReaderTest.txt");
File dstFile = new File("txt/BufferedWriterTest.txt");

FileReader fr = new FileReader(srcFile);
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(dstFile);
BufferedWriter bw = new BufferedWriter(fw);

char[] str = new char[1024];

while ((br.read(str)) != -1) {
   bw.write(str);
}

br.close();
bw.flush();
bw.close();

2.4 InputStream-Reader

2.5 OutputStream-Writer

3 非流式部分

3.1 RandomAccessFile

特點(diǎn)

1、既可以讀也可以寫(xiě)。

RandomAccessFile不屬于InputStreamOutputStream類(lèi)系的它是一個(gè)完全獨(dú)立的類(lèi),所有方法(絕大多數(shù)都只屬于它自己)都是自己從頭開(kāi)始規(guī)定的,這里面包含讀寫(xiě)兩種操作。

2、可以指定位置讀寫(xiě)。

RandomAccessFile能在文件里面前后移動(dòng),在文件里移動(dòng)用的seek(),所以它的行為與其它的I/O類(lèi) 有些根本性的不同。總而言之,它是一個(gè)直接繼承Object的,獨(dú)立的類(lèi)。只有RandomAccessFile才有seek方法,而這個(gè)方法也只適用于文件。

功能

可以用于多線(xiàn)程分段下載,斷點(diǎn)續(xù)傳。

RandomAccessFile raf = new RandomAccessFile(file, "rw");

raf.seek(10);
raf.setLength(1000);

raf.writeBoolean(true);
raf.writeChar('a');

RandomAccessFile(File file, String mode)

參數(shù) mode 的值可選 "r":可讀,"w" :可寫(xiě),"rw":可讀性。

seek(int index):可以將指針移動(dòng)到某個(gè)位置開(kāi)始讀寫(xiě)。

setLength(long len):給寫(xiě)入文件預(yù)留空間。

3.2 NIO-FileChannel

Channel是對(duì)I/O操作的封裝。

FileChannel配合著ByteBuffer,將讀寫(xiě)的數(shù)據(jù)緩存到內(nèi)存中,然后以批量/緩 存的方式read/write,省去了非批量操作時(shí)的重復(fù)中間操作,操縱大文件時(shí)可 以顯著提高效率。

package site.exciter.learn.io;

import android.os.Build;

import androidx.annotation.RequiresApi;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.time.Duration;
import java.time.Instant;

public class FileChannelTest {
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static void main(String[] args) {
        File sourceFile = new File("/Users/exciter/Desktop/test-01.zip");
        File targetFile = new File("/Users/exciter/Desktop/test-02.zip");
        targetFile.deleteOnExit();
        try {
            targetFile.createNewFile();
        } catch (Exception e) {
            e.printStackTrace();
        }

        copyFileByFileChannel(sourceFile, targetFile);
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private static void copyFileByFileChannel(File sourceFile, File targetFile) {
        Instant begin = Instant.now();

        RandomAccessFile sourceRaf = null;
        RandomAccessFile targetRaf = null;

        try {
            sourceRaf = new RandomAccessFile(sourceFile, "r");
            targetRaf = new RandomAccessFile(targetFile, "rw");
        } catch (Exception e) {
            e.printStackTrace();
        }

        FileChannel sourceFileChannel = sourceRaf.getChannel();
        FileChannel targetFileChannel = targetRaf.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024);

        try {
            while (sourceFileChannel.read(byteBuffer) != -1) {
                byteBuffer.flip();
                targetFileChannel.write(byteBuffer);
                byteBuffer.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                sourceFileChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                targetFileChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("time:" + Duration.between(begin, Instant.now()).toMillis());
    }
}

關(guān)注木水小站 (zhangmushui.cn)和微信公眾號(hào)【木水Code】,及時(shí)獲取更多最新技術(shù)干貨。

?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1.IO流概述 (1)用來(lái)處理設(shè)備(硬盤(pán),控制臺(tái),內(nèi)存)間的數(shù)據(jù)。 (2)java中對(duì)數(shù)據(jù)的操作都是通過(guò)流的方...
    臨時(shí)_01e2閱讀 201評(píng)論 0 0
  • 6.IO流 6.1 File 系統(tǒng)中我們一眼看到的就是文件或者文件夾本質(zhì)是一個(gè)路徑(字符串);用字符串來(lái)表示這個(gè)路...
    ADMAS閱讀 480評(píng)論 0 0
  • 通常的IO操作,只要不是操作系統(tǒng)內(nèi)存的數(shù)據(jù),基本都是IO操作,常見(jiàn)的IO操作,一般都是 操作磁盤(pán)、網(wǎng)卡這些(串口這...
    軒居晨風(fēng)閱讀 816評(píng)論 0 1
  • 來(lái)源:拉勾教育Java就業(yè)集訓(xùn)營(yíng)[https://kaiwu.lagou.com/] IO流 IO流的概念 IO就...
    zhe11閱讀 288評(píng)論 0 0
  • (1)概念 文件在程序中是以流的形式來(lái)操作的。 流:是一組有順序的,有起點(diǎn)和終點(diǎn)的字節(jié)集合,是對(duì)數(shù)據(jù)傳輸?shù)目偡Q(chēng)或抽...
    NoBugException閱讀 3,910評(píng)論 0 10

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