I/O的學習之字節流

I/O的學習之字節流

今天的主要內容

  • File類的使用

    • File類概述和構造方法

    • File類的創建功能

    • File類的重命名和刪除功能

    • File類的判斷功能

    • File類的獲取功能

    • 案例:輸出指定目錄下指定后綴的文件名

    • 文件名稱過濾器的概述及使用

  • IO流

    • IO流概述

    • FileInputStream

    • FileOutputStream

    • IO流拷貝圖片

    • BufferedInputStream和BufferOutputStream拷貝

    • flush和close的區別

    • 流的標準異常處理代碼

    • IO流圖片加密

    • IO流(拷貝文件)

      • 在控制臺錄入文件的路徑,將文件拷貝到當前項目下
    • IO流(錄入數據拷貝到文件)

      • 獲取鍵盤輸入,并將輸入的信息寫入到text.txt中

File

一、File類(File類的概述和構造方法)

  1. File類的概述

    • File更應該叫做一個路徑

      • 文件路徑或者文件夾路徑

      • 路徑分為絕對路徑和相對路徑

      • 絕對路徑是一個固定的路徑,從盤符開始

      • 相對路徑相對于某個位置,在eclipse下是指當前項目下,在dos下指的當前路徑

    • 查看API

    • 文件和目錄路徑名的抽象表示形式

  2. 構造方法

    • File(String pathname):根據一個路徑得到File對象

    • File(String parent, String child):根據一個目錄和一個子文件/目錄得到File對象

    • File(File parent, String child):根據一個父File對象和一個子文件/目錄得到File對象(重點)

  3. 構造方法的使用

     public class TestFile_1 {
         public static void main(String[] args) {
             //File(String pathname):根據一個路徑得到File對象
             File file1 = new File("E:" + File.separator + "mytest" + File.separator + "testMy.txt");
             
             //File(String parent, String child)
             String child = "testMy.txt";
             File file2 = new File("E:" + File.separator + "mytest",child);
             
             //File(File parent, String child)
             //這種方法更好,因為可以對父路徑進行一些操作
             File parent = new File("E:" + File.separator + "mytest");
             File file3 = new File(parent,child);
             
             System.out.println(file3.exists());
             System.out.println(parent.exists());        
         }
     }
    

二、File類(File類的創建功能)

  • A:創建功能

    • public boolean createNewFile():創建文件 如果存在這樣的文件,就不創建了
    • public boolean mkdir():創建文件夾 如果存在這樣的文件夾,就不創建了
    • public boolean mkdirs():創建文件夾,如果父文件夾不存在,會幫你創建出來
  • 如果你創建文件或者文件夾忘了寫盤符路徑,那么,默認在項目路徑下。

三、File類(File類的重命名和刪除功能)

  • A:重命名和刪除功能

    • public boolean renameTo(File dest):把文件重命名為指定的文件路徑
    • public boolean delete():刪除文件或者空的文件夾
  • B:重命名注意事項

    • 如果路徑名相同,就是改名。
    • 如果路徑名不同,就是改名并剪切。
  • C:刪除注意事項:

    • Java中的刪除不走回收站。
    • 要刪除一個文件夾,請注意該文件夾內不能包含文件或者文件夾
  • 程序

      public class TestFileMethod {
          public static void main(String[] args) {
              File file = new File("E:" + File.separator + "myTest");
              
              //重命名myTest為myTest2
              System.out.println(file.renameTo(new File("E:" + File.separator + "myTest2")));
              
              //此時renameTo相當于剪切并重命名
              System.out.println(file.renameTo(new File("E:" + File.separator + "test" + File.separator + "myTest3")));       
          }
      }
    

四、File類(File類的判斷功能)

  • A:判斷功能
    • public boolean isDirectory():判斷是否是目錄
    • public boolean isFile():判斷是否是文件
    • public boolean exists():判斷是否存在
    • public boolean canRead():判斷是否可讀
      • setReadable(false)在Windows系統中不生效
      • 只在Windows中生效
    • public boolean canWrite():判斷是否可寫
      • setWritable(false)在Windows中也生效
    • public boolean isHidden():判斷是否隱藏

五、File類(File類的獲取功能)

  • A:獲取功能
    • public String getAbsolutePath():獲取絕對路徑
    • public String getPath():獲取路徑
    • public String getName():獲取名稱
    • public long length():獲取長度。字節數
    • public long lastModified():獲取最后一次的修改時間,毫秒值
      • 可格式化為正常日期
      • SimpleDateFormat sdf = new SimpleDateFormat();
      • sdf.format(new Date(file.lastModified));
    • public String[] list():獲取指定目錄下的所有文件和文件夾的名稱數組
    • public File[] listFiles():獲取指定目錄下的所有文件或者文件夾的File數組

六、File類(輸出指定目錄下指定后綴的文件名)

  • 需求:判斷E盤目錄及子目錄下是否有后綴名為.txt的文件,如果有,就輸出該文件名稱

    • 需要遞歸
  • 程序

      public class TestFile_2 {
          public static void main(String[] args) {
              File file = new File("E:/");
              
              findFile(file);
          }
      
          private static void findFile(File file) {
              // TODO Auto-generated method stub
              if(file.isDirectory()) {
                  File[] files = file.listFiles();
                  
                  if(files != null) {
                      for(int i = 0; i < files.length;i++) {
                          findFile(files[i]);
                      }               
                  }
              }else {
                  String fileName = null;
                  
                  if(file.getName().contains(".txt")) {
                      System.out.println(file);
                  }
              }
          }
      }
    

七、File類(文件名稱過濾器的概述及使用)

  • A:文件名稱過濾器的概述

    • @FunctionalInterface(函數式接口)
      public interface FileFilter

      • 只有一個accept方法
    • public String[] list(FilenameFilter filter)

    • public File[] listFiles(FileFilter filter)

  • 過濾器作用就是篩選我們需要的文件和文件夾信息

  • 常用方法

    • public String[] list(FilenameFilter filter)

    • public File[] listFiles(FileFilter filter)

  • 程序

    • 需求:返回E盤目錄及子目錄下是否有后綴名為.txt的文件

    • Code:

        public class TestFileFilter {
            public static void main(String[] args) {
                File file = new File("E:/");
                
                //返回E盤目錄及子目錄下是否有后綴名為.txt的文件 
                file.listFiles(new FileFilter() {
                    
                    @Override
                    public boolean accept(File file) {
                        // TODO Auto-generated method stub
                        if(file.isDirectory()) {
                            File[] files = file.listFiles();
                            
                            if(files != null) {
                                for(int i = 0;i < files.length;i++) {
                                    accept(files[i]);
                                }
                            }
                        }else {
                            if(file.getName().contains(".txt")) {
                                System.out.println(file);
                                return true;
                            }
                        }
                        return false;
                    }
                });
            }
        }
      

I/O

一、IO流(IO流概述及其分類)

  1. 概念

    • IO流用來處理設備之間的數據傳輸

    • Java對數據的操作是通過流的方式

    • Java用于操作流的類都在IO包中

    • 流按流向分為兩種:輸入流,輸出流。

    • 流按操作類型分為兩種:

      • 字節流 : 字節流可以操作任何數據,因為在計算機中任何數據都是以字節的形式存儲的

      • 字符流 : 字符流只能操作純字符數據,比較方便。

  2. IO流常用父類

    • 字節流的抽象父類:

      • InputStream

      • OutputStream

    • 字符流的抽象父類:

      • Reader

      • Writer

  3. IO程序書寫

    • 使用前,導入IO包中的類

    • 使用時,進行IO異常處理

    • 使用后,釋放資源

二、IO流(FileInputStream)

  • read()一次讀取一個字節

  • 程序

      public class TestFileInputStream {
          public static void main(String[] args) {
              File file = new File("E:" + File.separator + "test" + File.separator + "test.txt");
              
              //創建輸入流
              FileInputStream fileInputStream = null;
              int b = 0;
              
              try {
                  fileInputStream = new FileInputStream(file);
                  
                  //read()一次讀取一個字節
                  while((b = fileInputStream.read()) != -1) {
                      System.out.print((char)b);
                  }
                  
                  fileInputStream.close();
              } catch (FileNotFoundException e1) {
                  // TODO Auto-generated catch block
                  e1.printStackTrace();
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              } 
          }
      }
      /*
       * 在JDK1.8中輸出結果為:
       * --------------
       * hahahahaha
       * --------------
       * */
    

三、IO流(read()方法返回值為什么是int)

* 因為字節輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是以二進制形式的存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111,那么這11111111是byte類型的-1,我們的程序是遇到-1就會停止不讀了,后面的數據就讀不到了,所以在讀取的時候用int類型接收,如果11111111會在其前面補上24個0湊足4個字節,那么byte類型的-1就變成int類型的255了這樣可以保證整個數據讀完,而結束標記的-1就是int類型

四、IO流(FileOutputStream)

  • write()一次寫出一個字節
    • 雖然write的參數是int,但是在寫入文件的時候仍舊是一個字節一個字節去寫入

        public class TestFileOutputStream {
            public static void main(String[] args) {
                OutputStream osOutputStream = null;
                try {
                    osOutputStream = new FileOutputStream(new File("E:/test/test2.txt"));           
                    osOutputStream.write(97);   //在test2.txt中寫入a;
                    osOutputStream.close();
                } catch (FileNotFoundException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
      

五、IO流(FileOutputStream追加)

  • public FileOutputStream(File file,
    boolean append)
    throws FileNotFoundException

  • FileOutputStream fos = new FileOutputStream("bbb.txt",true); //如果沒有bbb.txt,會創建出一個bbb.txt

六、IO流(拷貝圖片)

  • 利用字節流完成圖片的拷貝

  • 程序

      public class TestCopyPic {
          public static void main(String[] args) {
              InputStream iStream = null;
              OutputStream oStream = null;
              
              try {
                  iStream = new FileInputStream(new File("E:/test/1.jpg"));
                  oStream = new FileOutputStream(new File("E:/test/2.jpg"));
                  
                  //進行圖片的拷貝
                  int b = 0;
                  
                  //單個字節進行拷貝
                  while((b = iStream.read()) != -1) {
                      oStream.write(b);
                  }   
                  
                  //關流
                  iStream.close();
                  oStream.close();
              } catch (IOException e) {
                  // TODO: handle exception
                  e.printStackTrace();
              }
          }
      }
    

七、IO流(拷貝音頻文件畫原理圖)

image

八、IO流(字節數組拷貝之available()方法)

  • public int available()
    throws IOException

    • Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream(返回)
  • available()獲取讀的文件所有的字節個數

  • int read(byte[] b):一次讀取一個字節數組

  • write(byte[] b):一次寫出一個字節數組

  • 程序

      public class TestCopyPic_2 {
          public static void main(String[] args) {
              FileInputStream fiStream = null;
              FileOutputStream foStream = null;
              
              try {
                  fiStream = new FileInputStream(new File("E:/test/1.jpg"));
                  foStream = new FileOutputStream(new File("E:/test/3.jpg"));
                  
                  /*int b = fiStream.available();    //獲取文件的字節個數
                  System.out.println(b);*/
                  
                  //根據文件大小做一個字節數組
                  byte[] arr = new byte[fiStream.available()];
                  
                  //將文件上的所有字節讀取到數組中
                  fiStream.read(arr); 
              
                  //將數組中的所有字節一次寫到了文件上     
                  foStream.write(arr);
                  
                  fiStream.close();
                  foStream.close();
                  
              }catch (IOException e) {
                  // TODO: handle exception
                  e.printStackTrace();
              }
          }
      }
      /*
      
      此時拷貝成功
      
      */
    
  • 弊端:有可能會內存溢出

九、IO流(定義小數組)

  • write(byte[] b)

  • write(byte[] b, int off, int len)寫出有效的字節個數

  • 注意理解:read(byte[] b)方法的工作實質
    * 返回的是有效字節的個數
    * 因此不能直接輸出字節數組內容
    * 而是只輸出到有效字節位數即可

  • read(byte[] b)的理解
    public class TestCopyPic_3 {
    public static void main(String[] args) {
    FileInputStream fiStream = null;
    FileOutputStream foStream = null;

              try {
                  //此時test.txt的大小為三個字節,內容為abc
                  fiStream = new FileInputStream(new File("E:/test/test.txt"));
                  
                  foStream = new FileOutputStream(new File("E:/test/test1.txt"));
                  
                  byte[] arr = new byte[2];                //定義兩個字節大小的數組
                  
                  System.out.println("======第一次讀取時:======");
                  int a = fiStream.read(arr);
                  System.out.println("第一次讀取時的有效字節個數;" + a);                   //a為讀到的有效字節個數
                                  
                  System.out.print("第一次讀取時的字節數組中內容;");
                  for(byte b : arr) {                      //遍歷當前數組
                      System.out.print(b + "  ");
                  }
                  
                  System.out.println("\n======第二次讀取時:======");
                  int a2 = fiStream.read(arr);
                  System.out.println("第二次讀取時的有效字節個數;" +a2);
                  
                  System.out.print("第二次讀取時的字節數組中內容;");
                  for(byte b : arr) {
                      System.out.print(b + "  ");
                  }
                  
                  fiStream.close();
                  foStream.close();
                  
              }catch (IOException e) {
                  // TODO: handle exception
                  e.printStackTrace();
              }
          }
      }
      /*
       *  ======第一次讀取時:======
          第一次讀取時的有效字節個數;2
          第一次讀取時的字節數組中內容;97  98  
          ======第二次讀取時:======
          第二次讀取時的有效字節個數;1                         //由于字節數組大小為3,而第二次讀取時,文件中只有一個c
          第二次讀取時的字節數組中內容;99  98                   //原98的位置沒有被覆蓋,照常輸出
       * */
    
  • 小數組實圖片的拷貝

      public static void main(String[] args) {
          FileInputStream fiStream = null;
          FileOutputStream foStream = null;
          
          try {
              //此時test.txt的大小為三個字節,內容為abc
              fiStream = new FileInputStream(new File("E:/test/1.jpg"));          
              foStream = new FileOutputStream(new File("E:/test/copy.jpg"));
              
              int len = 0;
              byte[] arr = new byte[1024];        //1kb
              
              while((len = fiStream.read(arr)) != -1) {
                  foStream.write(arr, 0, len);            //將有效字節寫入
              }
              
              fiStream.close();
              foStream.close();
          } catch(IOException e) {
              e.printStackTrace();
          }
      }
    

十、IO流(BufferedInputStream和BufferOutputStream拷貝)

  • A:緩沖思想

    • 字節流一次讀寫一個數組的速度明顯比一次讀寫一個字節的速度快很多,

    • 這是加入了數組這樣的緩沖區效果,java本身在設計的時候,也考慮到了這樣的設計思想(裝飾設計模式后面講解),所以提供了字節緩沖區流

    • BufferedInputStream和BufferedOutputStream減少了內存到硬盤的讀和寫的次數,提高了效率。

  • 原理圖

    image
  • B.BufferedInputStream

    • BufferedInputStream內置了一個緩沖區(數組)

    • 從BufferedInputStream中讀取一個字節時,BufferedInputStream會一次性從文件中讀取8192個, 存在緩沖區中, 返回給程序一個

    • 程序再次讀取時, 就不用找文件了, 直接從緩沖區中獲取

    • 直到緩沖區中所有的都被使用過, 才重新從文件中讀取8192個

  • C.BufferedOutputStream

    • BufferedOutputStream也內置了一個緩沖區(數組)

    • 程序向流中寫出字節時, 不會直接寫到文件, 先寫到緩沖區中

    • 直到緩沖區寫滿, BufferedOutputStream才會把緩沖區中的數據一次性寫到文件里

  • 注意BufferedInoutStream和BufferedOutputStream在new時不拋出異常

  • 程序

      public static void main(String[] args) {
          FileInputStream fiStream = null;
          FileOutputStream foStream = null;
          
          BufferedInputStream biStream = null;
          BufferedOutputStream boStream = null;
          
          try{
              fiStream = new FileInputStream(new File("E:/test/1.jpg"));
              foStream = new FileOutputStream(new File("E:/test/copy.jpg"));
              
              //創建BufferedInputStream和BufferedOutputStram
              biStream = new BufferedInputStream(fiStream);
              boStream = new BufferedOutputStream(foStream);
              
              //復制
              int b = 0;
              while((b = biStream.read())!= -1) {
                  boStream.write(b);
              }
              
              biStream.close(); //只關閉包裝后的流即可
              boStream.close();
              
          }catch(IOException e) {
              e.printStackTrace();
          }       
      }
    
  • E.小數組的讀寫和帶Buffered的讀取哪個更快?

    • 定義小數組如果是8192個字節大小和Buffered比較的話

    • 定義小數組會略勝一籌,因為讀和寫操作的是同一個數組

    • 而Buffered操作的是兩個數組

    • BufferedOutputStream的源碼中顯示的是:在BufferedOutputStream類中自己定義了一個DEFAULT_BUFFER_SIZE = 8192的字節數組,作為緩存

十一、IO流(flush和close方法的區別)

  • public void flush() throws IOException(針對緩沖流而言的)

    • Flushes this output stream and forces any buffered output bytes to be written out.

    • The flush method of OutputStream does nothing.

  • flush()方法

    • 用來刷新緩沖區的,刷新后可以再次寫出
  • close()方法

    • 用來關閉流釋放資源的的,如果是帶緩沖區的流對象的close()方法,不但會關閉流,還會再關閉流之前刷新緩沖區,關閉后不能再寫出

十二、IO流(字節流讀寫中文)

  • 字節流讀取中文的問題

    • 字節流在讀中文的時候有可能會讀到半個中文,造成亂碼
  • 字節流寫出中文的問題

    • 字節流直接操作的字節,所以寫出中文必須將字符串轉換成字節數組
      * String中的getBytes方法
      * oStream.write("I love you".getBytes());

    • 寫出回車換行 write("\r\n".getBytes());

  • 注意:string和byte之間的轉化
    * String->byte[]
    * String中的getBytes方法
    * oStream.write("I love you".getBytes());

      * byte[]->String
          * String中的構造方法
              String(byte[] bytes, int offset, int length)
          * System.out.println(new String(bArr,0,len));
    

十三、IO流(流的標準處理異常代碼一)

  • finally的嵌套使用

  • 程序

      public static void main(String[] args) throws IOException{
          FileInputStream fiStream = null;
          FileOutputStream foStream = null;
          
          try {
              fiStream = new FileInputStream(new File("E:/test/1.jpg"));
              foStream = new FileOutputStream("E:/test/copy.jpg");
              
              //doWork
              byte[] bArr = new byte[1024 * 3];
              int len = 0;
              
              while((len = fiStream.read(bArr)) != -1) {
                  foStream.write(bArr,0,len);
              }
          } finally {
              try {
                  if(fiStream != null)
                      fiStream.close();       
              }finally {                          //確保至少有一個流可關閉
                  if(foStream != null) {     
                      foStream.close();
                  }
              }           
          }
      }
    

十四、IO流(流的標準處理異常代碼二)1.7版本

  1. 不需要寫關閉流的代碼
  2. InputStream和OutputStream實現了Closable接口,Closable實現了AutoClosable接口
  3. 只要實現了AutoClosable接口就會被自動調用從而自動關閉流
  • 程序

      public static void main(String[] args) throws IOException{
          //iStream和oStream的定義不可以寫在try外面
          
          try(
              //流的創建
              InputStream iStream = new FileInputStream("E:/test/1.jpg");
              OutputStream oStream = new FileOutputStream("E:/text/copy.jpg");
          ){
              //流操作
              int len = 0;
              byte[] bArr = new byte[1024 * 3];
              
              while((len = iStream.read(bArr)) != -1){
                  oStream.write(bArr,0,len);          
              }
          }
          //流會自動關閉
      }
    

十五、IO流(圖片加密)

  • 給圖片加密

      public static void main(String[] args) throws IOException{
          try(
              //流的創建
              BufferedInputStream  bInputStream = new BufferedInputStream(new FileInputStream("E:/test/1.jpg"));
              BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream("E:/test/copyJiaMi.jpg"));
          ){
              //文件復制加密
              int b = 0;
              while((b = bInputStream.read()) != -1) {
                  bOutputStream.write(b ^ 123);
              } 
          }
      }
    
  • 給圖片解密

      public static void main(String[] args) throws IOException{
          try(
                  //流的創建
                  BufferedInputStream  bInputStream = new BufferedInputStream(new FileInputStream("E:/test/copyJiaMi.jpg"));
                  BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream("E:/test/copyJieMi.jpg"));
              ){
                  //文件復制解密
                  int b = 0;
                  while((b = bInputStream.read()) != -1) {
                      bOutputStream.write(b ^ 123);
                  } 
              }
      }
    

十六、IO流(拷貝文件)

  • 在控制臺錄入文件的路徑,將文件拷貝到當前項目下

  • 程序

    • 分析

      1. 定義getFile()方法來獲取用戶輸入并判斷
      2. 主方法中實現文件的拷貝
      3. 注意面向對象的特點,盡量寫出易讀的代碼
    • Code

        public class TestIO_7 {
            public static void main(String[] args) throws IOException{
                //創建輸入輸出流對象
                BufferedInputStream biStream = null;
                BufferedOutputStream bOutputStream = null;
                
                try {
                    //實例化流
                    biStream = new BufferedInputStream(new FileInputStream(getFile()));
                    bOutputStream = new BufferedOutputStream(new FileOutputStream("des.jpg"));
                    
                    //文件拷貝
                    int b = 0;
                    while((b = biStream.read()) != -1) {
                        bOutputStream.write(b);
                    }
                }finally {
                    //關閉流
                        try {
                            if(biStream != null)
                                biStream.close();
                        }finally {
                            bOutputStream.close();
                        }           
                    }       
                }
            /*
             * 定義getFile()方法
             *      1. 獲取用戶輸入
             *      2. 判斷合法性,不合法重新輸入
             *      3. 封裝成為File對象后返回
             * */
            
            public static File getFile() {
                //獲取用戶輸入
                Scanner input = new Scanner(System.in);     
                File file = null;
                
                System.out.print("請輸入源文件路徑: ");
                while(true) {
                    String line = input.nextLine();
                    file = new File(line);                      //封裝為File對象,方便判斷是否為文件
                    
                    if(file.isFile()) {
                        break;
                    }
                    else {
                        System.out.println("您輸入的文件不存在,請重新輸入");
                    }
                }       
                return file;
            }   
        }
      

十七、IO流(錄入數據拷貝到文件)

  • 將鍵盤錄入的數據拷貝到當前項目下的text.txt文件中,鍵盤錄入數據當遇到quit時就退出
  • 程序

      public class TestIO_8 {
          public static void main(String[] args) throws IOException{
              //接受用戶輸入
              Scanner input = new Scanner(System.in);
              System.out.println("請輸入內容:");
              
              StringBuffer line = new StringBuffer();
              String str;
              
              while(!input.hasNext("quit")) {
                  str = input.nextLine();
                  line.append(str);
              }
              
              //將內容寫入文件
              writeFile(line.toString());
          }
      
          private static void writeFile(String string) throws IOException{
              // TODO Auto-generated method stub
              try(
                  //創建輸出流對象
                  BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream("text.txt"));
              ){
                  //將內容寫入文件
                  bOutputStream.write(string.getBytes());
              }   
          }
      }
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容