java基礎IO

1)Java中有幾種類型的流

1、基於字節操作的I/O接口:InputStream和OutputStream

2、基於字符操作的I/O接口:Writer和Reader

3、基於磁盤操作的I/O接口:File

4、基於網絡操作的I/O接口:Socket(不在java.io包下)

分類

1、按流的方向:輸入流,輸出流

2、按流的功能:節點流,處理流

3、按處理單位:字節流,字符流

2)四個基本抽象流,頂級接口

inputStream:字節輸入流

 

outputStream:字節輸出流

 

Reader:字符輸入流

 

Writer:字符輸出流

3)字節輸入流類型(字節輸出流類似)

ByteArrayInputStream:字節數組輸入流,該類的功能就是從字節數組(byte[])中進行以字節爲單位的讀取,也就是將資源文件都以字節的形式存入到該類中的字節數組中去,我們拿也是從這個字節數組中拿

PipedInputStream:管道字節輸入流,它和PipedOutputStream一起使用,能實現多線程間的管道通信

FilterInputStream :裝飾者模式中處於裝飾者,具體的裝飾者都要繼承它,所以在該類的子類下都是用來裝飾別的流的,也就是處理類。具體裝飾者模式在下面會講解到,到時就明白了

BufferedInputStream:緩衝流,對處理流進行裝飾,增強,內部會有一個緩存區,用來存放字節,每次都是將緩存區存滿然後發送,而不是一個字節或兩個字節這樣發送。效率更高

DataInputStream:數據輸入流,它是用來裝飾其它輸入流,它“允許應用程序以與機器無關方式從底層輸入流中讀取基本 Java 數據類型”

FileInputSream:文件輸入流。它通常用於對文件進行讀取操作

ObjectInputStream:對象輸入流,用來提供對“基本數據或對象”的持久存儲。通俗點講,也就是能直接傳輸對象(反序列化中使用,使用類需要繼承Serializable類)。

3)字符輸入流

CharReader、StringReader 是兩種基本的介質流,它們分別將Char 數組、String中讀取數據。PipedReader 是從與其它線程共用的管道中讀取數據。
BufferedReader 很明顯就是一個裝飾器,它和其子類負責裝飾其它Reader 對象。
FilterReader 是所有自定義具體裝飾流的父類,其子類PushbackReader 對Reader 對象進行裝飾,會增加一個行號。
InputStreamReader 是一個連接字節流和字符流的橋樑,它將字節流轉變爲字符流。FileReader 可以說是一個達到此功能、常用的工具類,在其源代碼中明顯使用了將FileInputStream 轉變爲Reader 的方法。
4)字節流字符流使用範圍

字節流一般用來處理圖像,視頻,以及PPT,Word類型的文件。字符流一般用於處理純文本類型的文件,如TXT文件等

5)System類

 System.in(標準輸入),通常代表鍵盤輸入。

System.out(標準輸出):通常寫往顯示器。

System.err(標準錯誤輸出):通常寫往顯示器。

6)使用了裝飾者設計模式

7)JDK1.8新增流操作Steam

詳細

8)緩存I/O

先將I/O的數據緩存到文件系統的頁緩存(先被拷貝到操作系統的內核),然後纔會從操作系統內核的緩衝區拷貝到應用程序的地址空間。

即緩存I/O需要在應用程序地址空間和內核進行多次數據拷貝操作,多cpu造成很大的開銷。

總結:IO需要進行兩個階段

1. 等待數據準備 
2. 將數據從內核拷貝到進程中 

9)阻塞I/O(blocking IO)

在linux默認情況下所以的socket都是阻塞的。

此時用戶線程在IO過程中被阻塞,不能做任何事情,對CPU的資源利用率不高。

例:你在釣魚的時候需要誘餌,只能先回家拿,拿好了才能回來繼續釣魚,沒拿到之前釣魚行爲是阻塞的不進行的。

10)非阻塞I/O(nonblocking IO)

linux下,可以通過設置socket使其變爲non-blocking。

流程:當用戶進程發起IO請求時,如果內核(kernel)中的數據並未準備好,那麼它並不會block進程,而是放回一個error。

當用戶線程發起一個IO read請求時,並不需要阻塞等待,而是馬上得到一個結果。如果結果是error,說明數據並未準備好,那麼線程可以再次發起read請求,直到內核中數據準備完畢,並且又再次收到用戶線程的read請求,那麼它會馬上把數據從內核中拷貝到用戶內存中去,然後返回。

nonblocking IO的特點是用戶進程需要不斷的主動詢問內核(kernel)數據好了沒有。

11)多路複用I/O(IO multiplexing)

即select,poll,epoll,也稱爲事件驅動。

它的基本原理就是select,poll,epoll(都是系統調用)這個function會不斷的輪詢所負責的所有socket,當某個socket有數據到達了(到達內核),就通知用戶進程,再把數據拷貝到用戶內存中。

當用戶進程調用了select,那麼整個進程會被block,而同時,kernel會“監視”所有select負責的socket,當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操作,將數據從kernel拷貝到用戶進程。

所以總的看來似乎和非阻塞IO差多少,而且還多了個系統調用。事實上性能可以說還比非阻塞差點(處理的連接數不是很高的話)。但它的優勢在於可以同時監控多個IO連接。

12)異步IO(asynchronous IO)

發起read操作後進程立馬返回,整個Io過程不會產生任何block。kernel會等等數據準備完成,然後將數據拷貝到用戶內存。當這一切都完成後,kernel會給用戶進程發送一個signal,告訴它read操作完成了。

13)select

int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

通過三個文件描述符和超時機制監控

readfds可讀

writefds可寫

exceptfds可except

timeout或者超時timeout指定等待時間,如果立即返回設爲null即可),函數返回。

14)poll

int poll (struct pollfd *fds, unsigned int nfds, int timeout);
struct pollfd {
    int fd; /* file descriptor */
    short events; /* requested events to watch 監控的事件*/
    short revents; /* returned events witnessed 發生的事件*/
};

可以看到poll使用的是pollfd的指針實現,而不是像select一樣使用三個位圖。

15)epoll

引用來源:作者:人云思雲
鏈接:https://segmentfault.com/a/1190000003063859

epoll操作過程需要三個接口,分別如下:

int epoll_create(int size);//創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
1. int epoll_create(int size);
創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大,這個參數不同於select()中的第一個參數,給出最大監聽的fd+1的值,參數size並不是限制了epoll所能監聽的描述符最大個數,只是對內核初始分配內部數據結構的一個建議。
當創建好epoll句柄後,它就會佔用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須調用close()關閉,否則可能導致fd被耗盡。

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
函數是對指定描述符fd執行op操作。
- epfd:是epoll_create()的返回值。
- op:表示op操作,用三個宏來表示:添加EPOLL_CTL_ADD,刪除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分別添加、刪除和修改對fd的監聽事件。
- fd:是需要監聽的fd(文件描述符)
- epoll_event:是告訴內核需要監聽什麼事,struct epoll_event結構如下:

struct epoll_event {
  __uint32_t events;  /* Epoll events */
  epoll_data_t data;  /* User data variable */
};

//events可以是以下幾個宏的集合:
EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符可以寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設爲邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裏
3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待epfd上的io事件,最多返回maxevents個事件。
參數events用來從內核得到事件的集合,maxevents告之內核這個events有多大,這個maxevents的值不能大於創建epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函數返回需要處理的事件數目,如返回0表示已超時。


epoll對文件描述符的操作有兩種模式:LT(level trigger)和ET(edge trigger)。LT模式是默認模式,LT模式與ET模式的區別如下:
  LT模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用epoll_wait時,會再次響應應用程序並通知此事件。
  ET模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用epoll_wait時,不會再次響應應用程序並通知此事件。

同步和異步的區別

只有異步IO是異步IO,
其他3種:阻塞IO、非阻塞IO、多路複用IO都是同步的。
這是因爲其他三種IO在執行真實IO操作的過程中都有進程阻塞的階段,而異步IO在整個過程中進程都沒有被阻塞。非阻塞IO在內核數據就緒,拷貝到用戶空間的階段也是阻塞的,因此也是同步IO。

刷題時間到劍指offer走起

題目描述

請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。 例如

adee
sfcs
abce

 

矩陣中包含一條字符串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因爲字符串的第一個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。

public class Solution {
    int[][] shuijiao = {{1,0},{-1,0},{0,1},{0,-1}};
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
        boolean[] vis = new boolean[matrix.length];//申請標記數組,訪問過的爲
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(matrix[cols*i+j] == str[0]){//找的第一個相同的
                    vis[cols*i+j] = true;
                    if(dfs(matrix, rows, cols, str, i, j, 1, vis) == true){
                        return true;
                    }
                    vis[cols*i+j] = false;//來到這裏說明沒有找的變回初始化
                }
            }
        }
        return false;
    }
    boolean dfs(char[] matrix, int rows, int cols, char[] str, int i, int j, int len, boolean[] vis){
        if(len == str.length)
                return true;
        int l,r;
        boolean f = false;
        for(int k = 0; k < 4; k++){
            l = i + shuijiao[k][0];
            r = j + shuijiao[k][1];
            if(l >= 0 && l < rows && r >= 0 && r<cols && vis[cols*l+r] == false && matrix[cols*l+r] == str[len]){
                vis[cols*l+r] = true;
                f = dfs(matrix, rows, cols, str, l, r, len+1, vis);
                vis[cols*l+r] = false;
            }
            if(f == true)
                return true;
        }
        return false;
    }

}

 

 

 

 

 


 

 

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