1. 程式人生 > >IO與NIO

IO與NIO

連續 測試 import bsp 兩個 同時 col team 關閉

IO

流的概念: java中數據的傳輸以流的形式體現(向水在管道中流動一樣)

技術分享圖片

流的分類

流按流向分為:輸入流,輸出流。

輸入流:程序從外部讀取數據

輸出流:程序向外部寫出數據 流按操作數據分為兩種:字節流與字符流。

字節流:以字節為單位操作數據,可以操作任何數據,如文本,圖片,視頻

字符流:專門用來處理字符數據的流對象,處理字符比較方便(有行的概念),其實內部使用的還是字節流 流按功能分為兩種: 基本流(節點流) 和 過濾流(處理流)

基本流 : 直接讀取或寫入對象,提供基本功能

過濾流 : 將基本流包裝起來,提供一些額外功能

File類

用來描述文件或目錄,可以對文件或目錄進行操作

構造方法 File(String pathname) 通過將給定路徑名字符串轉換成抽象路徑名來創建一個新 File 實例。

File(String parent, String child) 根據 parent 路徑名字符串和 child 路徑名字符串創建一個新 File 實例。中間有沒有分隔符無所謂。

File(File parent, String child) 根據 parent 抽象路徑名和

child 路徑名字符串創建一個新 File 實例。

常用字段 static String separator 與系統有關的默認名稱分隔符。

windows下為\,Linux下為/ static String pathSeparator與系統有關的路徑分隔符字符。

windows下為;,Linux下為:

常用方法 文件和文件夾共有操作 boolean delete() 刪除此抽象路徑名表示的文件或目錄。

如果此路徑名表示一個目錄,則此目錄必須為空才能刪除. 徹底刪除,不會移動到回收站

boolean exists() 測試此抽象路徑名表示的文件或目錄是否存在。 String getAbsolutePath() 返回抽象路徑名的絕對路徑名字符串 String getCanonicalPath() 返回抽象路徑名的規範路徑名字符串。 會經過解析,..去掉 String getName() 返回由此抽象路徑名表示的文件或目錄的名稱。

String getParent() 返回此抽象路徑名的父路徑名的路徑名字符串,如果此路徑名沒有指定父目錄,則返回 null

String getPath() 將此抽象路徑名轉換為一個路徑名字符串。

boolean isAbsolute() 測試此抽象路徑名是否為絕對路徑名。

註意:toString方法返回路徑名 (構造方法傳什麽路徑,就顯示什麽路徑,不一定是絕 對路徑).

文件操作: boolean isFile() 測試此抽象路徑名表示的文件是否是一個標準文件。

long lastModified() 返回此抽象路徑名表示的文件最後一次被修改的時間。

long length() 返回由此抽象路徑名表示的文件的長度。

boolean renameTo(File dest) 重新命名此抽象路徑名表示的文件。如果文件路徑修改,帶有剪切功能

boolean canRead() 測試應用程序是否可以讀取此抽象路徑名表示的文件。

boolean canWrite() 測試應用程序是否可以修改此抽象路徑名表示的文件。

boolean createNewFile() 當且僅當不存在具有此抽象路徑名指定的名稱的文件時,原子地創建由此抽 象路徑名指定的一個新的空文件。

文件夾操作 boolean isDirectory() 測試此抽象路徑名表示的文件是否是一個目錄。

String[] list() 返回由此抽象路徑名所表示的目錄中的文件和目錄的名稱所組成字符串數組。

String[] list(FilenameFilter filter) 返回由包含在目錄中的文件和目錄的名稱所組成的字符串數組,這一目錄是通過滿足指定過濾器的抽象路徑名來表示的。

File[] listFiles() 返回一個抽象路徑名數組,這些路徑名表示此抽象路徑名所表示目錄中的文件。

File[] listFiles(FileFilter filter) 返回表示此抽象路徑名所表示目錄中的文件和目錄的抽象路徑名數組, 這些路徑名滿足特定過濾器。

static File[] listRoots() 列出可用的文件系統根目錄。 windows為所有盤符,Linux/ boolean mkdir() 創建此抽象路徑名指定的目錄。

boolean mkdirs() 創建此抽象路徑名指定的目錄,包括創建必需但不存在的父目錄。

註意:

ist方法返回的是文件名,listFiles返回的是文件,包含全路徑名.

後者更常用FileFilter為一個接口,有一個方法 boolean accept(File pathname)

測試指定抽象路徑名是否應該包含在某個路徑名列表中。

特點:

字節流 InputStream * 字節輸入流的抽象父類

FileInputStream * 文件輸入流(基本流,用於對文件的讀取)

FilterInputStream * 過濾流的父類

BufferedInputSteam * 緩沖流(過濾流,提供緩沖功能)

ByteArrayInputStream * 字節數組輸入流(基本流,可以讀取字節數組中的數據)

OutputStream * 字節輸出流的抽象父類

FileOutputStream * 文件輸出流(基本流,用於對文件的寫入)

FilterOutputStream * 過濾流的父類

BufferedOutputStream * 緩沖流(過濾流,提供緩沖功能)

PrintStream * 打印流(過濾流,方便打印各種類型的數據,不會拋異常,可指定自動刷新,不能追加內容)

ByteArrayOutputStream * 字節數組輸出流(基本流,可以將數據寫入到字節數組中)

* 字符流 Reader * 字符輸入流的抽象父類

InputStreamReader * 字節字符轉換流(過濾流,可以將字節流轉換為字符流,以字符讀取,比較方便)

FileReader * 字符文件輸入流(基本流,用於對字符文件的讀取,以當前項目編碼)

BufferedReader * 緩沖流(過濾流,提供緩沖功能,可以讀一行)

Writer * 字符輸出流的抽象父類

OutputStreamWriter * 字節字符轉換流(過濾流,可以將字符流轉換為字節流,以字符寫入,比較方便)

FileWriter * 字符文件輸出流(基本流,用於對字符文件的寫入,以當前項目編碼)

BufferedWriter * 緩沖流(過濾流,提供緩沖功能,可以寫一個新行)

PrintWriter * 字符打印流(過濾流,方便打印各種類型的數據,不會拋異常,某些方法可指定自動刷新 printlnprintf format,有換行方法,可直接跟字節流打交道,不能追加內容)

NIO

NIO是為了彌補IO操作的不足而誕生的,NIO的一些新特性有:非阻塞I/O,選擇器,緩沖以及管道。 

NIO中的幾個基礎概念

  1.Channel

  2.Buffer

  3.Selector

管道(Channel),緩沖(Buffer) ,選擇器( Selector)是其主要特征。

NIO中有幾個比較關鍵的概念:Channel(通道),Buffer(緩沖區),Selector(選擇器)。

首先從Channel說起吧,通道,顧名思義,就是通向什麽的道路,為某個提供了渠道。

Channel是雙向的,既可用來進行讀操作,又可用來進行寫操作。

基於緩沖區對數據進行讀取或者是寫入

可以異步的讀取與寫入

以下是常用的幾種通道:

FileChannel:可以從文件讀或者向文件寫入數據

SocketChanel:以TCP來向網絡連接的兩端讀寫數據

ServerSocketChannel:能夠監聽客戶端發起的TCP連接,並為每個TCP連接創建一個新的

SocketChannel來進行數據讀寫

DatagramChannel:以UDP協議來向網絡連接的兩端讀寫數據

Buffer(緩沖區),是NIO中非常重要的一個東西,在NIO中所有數據的讀和寫都離不開Buffer。比如上面的一段代碼中,讀取的數據時放在byte數組當中,而在NIO中,讀取的數據只能放在Buffer中。同樣地,寫入數據也是先寫入到Buffer中。

Buffer,故名思意,緩沖區,實際上是一個容器,是一個連續數組。Channel提供從文件、網絡讀取數據的渠道,但是讀取或寫入的數據都必須經由Buffer

Buffer是一個頂層父類,它是一個抽象類,常用的Buffer的子類有:

ByteBuffer

IntBuffer

CharBuffer

LongBuffer

DoubleBuffer

FloatBuffer

ShortBuffer

  如果是對於文件讀寫,上面幾種Buffer都可能會用到。但是對於網絡讀寫來說,用的最多的是

ByteBuffer。

栗子:

緩沖區與管道

package cn.Fileoperation;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;

public class TheConduit {
    static Scanner input=new Scanner(System.in);
    public static void main(String[] args) {
            //創建
            //establish();
            //復制轉移
            //transfer();
    }
  //復制轉移
    private static void transfer() {
        System.out.println("文件的路徑+文件名");
        String one=input.next();
        System.out.println("想要文件信息的文件的路徑+文件名");
        String two=input.next();
        //創建file對象 ,兩個路徑
        File onefile=new File(one);
        File twofile=new File(two);
        //創建 輸入 輸出流
        FileInputStream fileInputStream=null;//輸入
        FileOutputStream fileOutputStream=null;//輸出
        //創建管道 用於 輸入 輸出
        FileChannel onechannel=null;//輸入
        FileChannel twochannel=null;//輸出
        //實例化 輸入 輸出
        try {
            fileInputStream=new FileInputStream(onefile);
            fileOutputStream=new FileOutputStream(twofile);
            //實例化管道
            onechannel=fileInputStream.getChannel();
            twochannel=fileOutputStream.getChannel();
            //創建緩沖區
            ByteBuffer  buffer= ByteBuffer.allocate(1024);
            //定義變量接去a文件的數據
            int num=0;
            while ((num=onechannel.read(buffer))!=-1){
                //切換模式
                buffer.flip();
                twochannel.write(buffer);//真實寫入
                //清除緩沖
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                twochannel.close();
                onechannel.close();
                fileOutputStream.close();
                fileInputStream.close();
                System.out.println("完事!!!!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 //創建
    private static void establish() {
        //寫模式
        System.out.println("需要一個路徑+文件名");
        String name=input.next();
        //創建一個文件對象
        File file=new File(name);
        //創建一個輸出流對象
        FileOutputStream fileOutputStream=null;
        //創建一管道對應的實體類
        FileChannel fileChannel=null;
        try {
            fileOutputStream=new FileOutputStream(file);//封裝
            fileChannel=fileOutputStream.getChannel();//獲取到管道
            ByteBuffer buffer=ByteBuffer.allocate(1024);//創建一個1024的緩沖區
            //創建一個數組來為緩沖區賦值
            String [] nams={"你","我","它","他","她"};
            //因為緩沖區是ByteBuffer 所以這裏需要轉化下
            for (String s:nams){
                buffer.put(s.getBytes());//把數組中的值循環添加到緩沖區中
            }
            //重置緩沖區  切換讀模式
            buffer.flip();
            //真正的寫入到文件中
            try {
                fileChannel.write(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    //關閉
                    fileChannel.close();
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

內存映射

就是把文件映射到電腦中的內存中,通過操作內存從而達到操作文件的目的

文件讀取文件方式

RandomAccessFile:隨機讀取,速度最慢

FileInputStream:流的方式讀取

BufferReader:緩存的方式讀取

MappedByteBuffer:內存映射,速度最快

內存映射的三種模式:MapMode

READ_ONLY:對緩沖區的內容只讀

READ_WRITE:對緩沖區的內容讀寫

PRIVATE:只會對緩沖區的內容進行修改,不會影響到真實的文件

栗子:

package cn.Fileoperation;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;

public class Memorymappings {
    static Scanner input=new Scanner(System.in);
    public static void main(String[] args) {
        mappings();
    }
    private static void mappings() {
        //創建一個管道
        FileChannel fileChannel=null;
        System.out.println("給個地址:");
        String file=input.next();
        try {
            RandomAccessFile randomAccessFile=new RandomAccessFile(file,"rw");
            //實例化一個管道
            fileChannel=randomAccessFile.getChannel();
            try {
                //創建一個內存文件映射
                MappedByteBuffer   buffer=fileChannel.map(FileChannel.MapMode.READ_ONLY,0,fileChannel.size());
                //創建一個緩沖區
                ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
                //創建一個byte數組,便於後續獲取數據
                byte [] bytes=new byte[1024];
                //獲取文件的大小
                long length=randomAccessFile.length();
                //設置開始時間
                long bageTime=System.currentTimeMillis();
                //循環
                for (int i=0;i<length;i+=1024){
                    if(length-i>1024){
                        buffer.get(bytes);
                    }else{
                        byteBuffer.get(new byte[(int)length-i]);
                    }
                }
                //設置結束時間
              long endTime=System.currentTimeMillis();
                System.out.println("使用內存映射的時間"+(bageTime-endTime));

                System.out.println("----------------------------------------------");
                System.out.println();

                bageTime=System.currentTimeMillis();//開始時間
                int num=0;
                while ((num=fileChannel.read(byteBuffer))!=-1){
                    byteBuffer.flip();  //重置緩沖區
                    byteBuffer.clear();//清空緩沖區
                }
                endTime=System.currentTimeMillis();//結束時間
                System.out.println("使用io的時間"+(bageTime-endTime));
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

文件鎖

目的:安全

FileLock:基於FileChannel對文件提供鎖的功能

分為兩種:

共享鎖:可以一起讀,只有一個寫,共享鎖的目的是為了防止別人獲取獨占鎖。

獨占鎖:只能有一個讀或寫,讀寫不能同時

栗子:

package cn.Fileoperation;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Scanner;
public class Lock {
    static Scanner input=new Scanner(System.in);
    public static void main(String[] args) {
       lock();
    }
    private static void lock() {
        FileChannel channel=null;
        FileLock lock=null;
        //獲取文件
        System.out.println("路徑:");
        String file=input.next();
        try {
            RandomAccessFile randomAccessFile=new RandomAccessFile(file,"rw");
            //獲取管道
            channel=randomAccessFile.getChannel();
            try {
                lock=channel.lock();//獨占鎖
                lock=channel.lock(0,channel.size(),true);//共享鎖
                System.out.println(lock.isShared());
                System.out.println(lock.isValid());
                //創建緩沖區
                ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
                System.out.println("寫:");
                String name=input.next();
                //向緩沖區寫入數據
                byteBuffer.put(name.getBytes());
                //切換模式
                byteBuffer.flip();
                //通道寫入數據
                channel.write(byteBuffer);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    lock.close();
                    channel.close();
                    System.out.println("完事!!!!");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

IO與NIO