日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

14:IO之字符字节流

發(fā)布時間:2023/12/19 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 14:IO之字符字节流 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

字節(jié)流:InputStream ???OutputStream?字節(jié)流:?FileInputStreamFileOutputStreamBufferedInputStreamBufferedOutputStream字符流:Writer ReaderFileReaderFileWriterBufferedReaderBufferedWriter

第一 ?IO流概述

一、概述:

IO流是來處理設備間的數(shù)據(jù)傳輸

1、特點:

1)流操作按照數(shù)據(jù)可分為字節(jié)流(處理所有的數(shù)據(jù))和字符流(處理文字,其中包含編碼表,可以指定編碼表防止了編碼表不同而產(chǎn)生亂碼的現(xiàn)象)

2)按照流向分可以分為輸出流和輸入流。

字節(jié)流的抽象基類:InputStream(讀)、OutputStream(寫)

字符流的抽象基類:Reader(讀)、Writer(寫)

注:此四個類派生出來的子類名稱都是以父類名作為子類名的后綴,以前綴為其功能;


第二 ?字符流

一、簡述:

1、字符流中的對象融合了編碼表。使用的是默認的編碼,即當前系統(tǒng)的編碼。

2、字符流只用于處理文字數(shù)據(jù),而字節(jié)流可以任何數(shù)據(jù)。

3、既然IO流是用于操作數(shù)據(jù)的,那么數(shù)據(jù)的最常見體現(xiàn)形式是文件。專門用于操作文件的子類對象:FileWriter、FileReader

二、寫入字符流

  • 數(shù)據(jù)的續(xù)寫是通過構造函數(shù) FileWriter(String s,boolean append),根據(jù)給定文件名及指示是否附加寫入數(shù)據(jù)的boolean值來構造FileWriter對象。為true時就是續(xù)寫,為false就是不續(xù)寫。?
  • 調用write()方法,將字符串寫入到流中。這里他本身沒有特定的寫方法都是繼承自父類的方法有寫單個字符:write(int?c),寫入字符數(shù)組:write(char[]?cbuf)這里的數(shù)組一般定義成1024的整數(shù)倍,不宜過大,過大容易造成內存溢出。寫入字符數(shù)組的某一部分:write(char[]?cbuf, int?off, int?len),寫入字符串:write(String?str),寫入字符串的某一部分:write(String?str, int?off, int?len)

  • ?*???
  • ?*?需求:在硬盤上,創(chuàng)建一個文件并寫入一些文字數(shù)據(jù)。??
  • ?*?找到一個專門用于操作文件的Writer子類對象。FileWriter。??后綴名是父類名。?前綴名是該流對象的功能。??
  • ?*/??
  • public?class?FileWriterDemo?{??
  • ????public?static?void?main(String[]?args)?{??
  • ????????method();//寫內容??
  • ????????method2();//續(xù)寫內容??
  • ????}??
  • ??????
  • ????/*??
  • ?????*?寫數(shù)據(jù)??
  • ?????*/??
  • ????public?static?void?method(){??
  • ????????FileWriter?fw?=?null;??
  • ????????try?{??
  • ????????????//創(chuàng)建一個FileWriter對象。該對象一被初始化就必須要明確被操作的文件。??
  • ????????????//該文件會被存放在指定的目錄下,如果該文件已經(jīng)存在,會被覆蓋??
  • ????????????//其實該步就是在明確數(shù)據(jù)要存放的目的地。??
  • ????????????fw?=?new?FileWriter("testwrite.txt");//?C:\\testwrite.txt??
  • ??????????????
  • ????????????//調用write方法,將字符串寫入到流中??
  • ????????????fw.write("asdsadafsd");??
  • ??????????????
  • ????????????//刷新流對象中的緩沖中的數(shù)據(jù)。??
  • ????????????//將數(shù)據(jù)刷到目的地中。??
  • //??????????fw.flush();??
  • ??????????????
  • ????????????//關閉流資源,但是關閉之前會刷新一次內部的緩沖中的數(shù)據(jù)。??
  • ????????????//將數(shù)據(jù)刷到目的地中。??
  • ????????????//和flush區(qū)別:flush刷新后,流可以繼續(xù)使用,close刷新后,會將流關閉。??
  • //??????????fw.close();??
  • ????????}?catch?(IOException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}finally{??
  • ????????????try?{??
  • ????????????????if(fw?!=?null)??
  • ????????????????????fw.close();??
  • ????????????}?catch?(IOException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??????
  • ????/*??
  • ?????*?在文件原有內容的基礎上續(xù)寫內容??
  • ?????*/??
  • ????public?static?void?method2(){??
  • ????????FileWriter?fw?=?null;??
  • ????????try?{??
  • ????????????fw?=?new?FileWriter("testwrite.txt",?true);??
  • ????????????fw.write("\r\nnihao\r\nxiexie");//\r\n是換行符\n是linux下的換行??
  • ????????}?catch?(IOException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}finally{??
  • ????????????if(fw?!=?null){??
  • ????????????????try?{??
  • ????????????????????fw.close();??
  • ????????????????}?catch?(IOException?e)?{??
  • ????????????????????e.printStackTrace();??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????}??
  • } ?
    ?
  • 三、讀取字符流

    • 創(chuàng)建一個文件讀取流對象,和指定名稱的文件相關聯(lián)。要保證該文件已經(jīng)存在,若不存在,將會發(fā)生異常FileNotFoundException。
    • 調用讀取流對象的read()方法。read():一次讀一個字符,且會繼續(xù)往下讀。(方法1)

      read()讀取單個字符。read(char[]?cbuf)將字符讀入數(shù)組。(方法2)其實都是按照每次只讀取一個字符的方式讀取的,只是讀到數(shù)組中會把讀取到的數(shù)據(jù)存放在數(shù)組中,起到一個臨時緩存的作用,提高了讀取效率。

    • 演示1
    • public static void main(String[] args) throws IOException {
    • FileReader fr = new FileReader("demo.txt");
    • int ch = 0;
    • while((ch=fr.read())!=-1){// abcde讀5次
    • System.out.println((char)ch);
    • fr.close();
    • }
    • 演示2
    • public class FileReaderDemo2 {
    • public static void main(String[] args) throws IOException {
    • FileReader fr = new FileReader("demo.txt");
    • /*
    • * 使用read(char[])讀取文本文件數(shù)據(jù)。
    • *
    • * 先創(chuàng)建字符數(shù)組。
    • */
    • char[] buf = new char[1024];
    • int len = 0;
    • while((len=fr.read(buf))!=-1){ // abcde讀1次,提高效率,是一個數(shù)組一個數(shù)組的讀
    • System.out.println(new String(buf,0,len));
    • }
    • /*
    • int num = fr.read(buf);//將讀取到的字符存儲到數(shù)組中。讀到幾個幾個變成數(shù)組
    • System.out.println(num+":"+new String(buf,0,num));
    • int num1 = fr.read(buf);//將讀取到的字符存儲到數(shù)組中。
    • System.out.println(num1+":"+new String(buf,0,num1));
    • int num2 = fr.read(buf);//將讀取到的字符存儲到數(shù)組中。
    • System.out.println(num2+":"+new String(buf));
    • */
    • ???fr.close();?
    • }


    四、文件的拷貝:

    原理:其實就是將磁盤下的文件數(shù)據(jù)讀取出來,然后寫入磁盤的一個文件中

    步驟:
    1、在硬盤上創(chuàng)建一個文件,用于存儲讀取出來的文件數(shù)據(jù)
    2、定義讀取流和文件關聯(lián)
    3、通過不斷讀寫完成數(shù)據(jù)存儲
    方式一:讀取一個字符,存入一個字符
    方式二:先將讀取的數(shù)據(jù)存入到內存中,再將存入的字符取出寫入硬盤
    4、關閉流資源:輸入流資源和輸出流資源。


  • 方法1
  • /*
  • * 思路:
  • * 1,需要讀取源,
  • * 2,將讀到的源數(shù)據(jù)寫入到目的地。
  • * 3,既然是操作文本數(shù)據(jù),使用字符流。
  • *
  • */
  • public class CopyTextTest {
  • public static void main(String[] args) throws IOException {
  • //1,讀取一個已有的文本文件,使用字符讀取流和文件相關聯(lián)。
  • FileReader fr = new FileReader("IO流_2.txt");
  • //2,創(chuàng)建一個目的,用于存儲讀到數(shù)據(jù)。
  • FileWriter fw = new FileWriter("copytext_1.txt");
  • //3,頻繁的讀寫操作。
  • int ch = 0;
  • while((ch=fr.read())!=-1){
  • fw.write(ch);
  • }
  • //4,關閉流資源。先關寫再關讀
  • fw.close();
  • fr.close();
  • }
  • }
  • 方法2
  • public class CopyTextTest_2 {
  • private static final int BUFFER_SIZE = 1024;
  • public static void main(String[] args) {
  • FileReader fr = null;
  • FileWriter fw = null;
  • try {
  • fr = new FileReader("IO流_2.txt");
  • fw = new FileWriter("copytest_2.txt");
  • //創(chuàng)建一個臨時容器,用于緩存讀取到的字符。
  • char[] buf = new char[BUFFER_SIZE];//這就是緩沖區(qū)。
  • //定義一個變量記錄讀取到的字符數(shù),(其實就是往數(shù)組里裝的字符個數(shù) )
  • int len = 0;
  • while((len=fr.read(buf))!=-1){
  • fw.write(buf, 0, len);
  • }
  • } catch (Exception e) {
  • // System.out.println("讀寫失敗");
  • throw new RuntimeException("讀寫失敗");
  • }finally{
  • if(fw!=null)
  • try {
  • fw.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • if(fr!=null)
  • try {
  • fr.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }

  • 第三 ?字符緩沖區(qū)

    一、寫入緩沖區(qū)BufferedWriter
  • /
  • * 緩沖區(qū)的出現(xiàn)就是為了提高操作流的效率
  • * 所以在創(chuàng)建緩沖區(qū)之前必須要先有流對象
  • *
  • * 緩沖區(qū)提供了一個跨平臺的換行符 new Line();
  • */
  • public class BufferedWriterDemo {
  • public static void main(String[] args) {
  • method();
  • }
  • public static void method() {
  • // 創(chuàng)建一個字符寫入流對象
  • FileWriter fw = null;
  • BufferedWriter bfw = null;
  • try {
  • fw = new FileWriter("buf.txt");
  • // 為了提高字符寫入流效率。加入了緩沖技術。其實緩沖區(qū)就是封裝了數(shù)組,不用自己定義數(shù)組,用起來更方便
  • // 只要將需要被提高效率的流對象作為參數(shù)傳遞給緩沖區(qū)的構造函數(shù)即可。
  • bfw = new BufferedWriter(fw);
  • for (int x = 0; x < 10; x++) {
  • bfw.write("abcds" + x);
  • bfw.newLine();// 換行在windows中相當于\r\n,在linux中相當于\n
  • }
  • // 記住,只要用到緩沖區(qū),就要記得刷新。
  • // bufw.flush();
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • try {
  • bfw.close();// 關閉緩沖區(qū)就是在關閉緩沖區(qū)中的流對象,關閉前刷新
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }
  • private static final String LINE_SEPARATOR = System.getProperty("line.separator");
  • //使用緩沖區(qū)的寫入方法將數(shù)據(jù)先寫入到緩沖區(qū)中。
  • // bufw.write("abcdefq"+LINE_SEPARATOR+"hahahha");
  • // bufw.write("xixiixii");
  • // bufw.newLine(); 行分隔,就不需要LINE_SEPARATOR,不過只在這里有效
  • // bufw.write("heheheheh");

  • 二、讀取流緩沖區(qū)BufferedReader

    該緩沖區(qū)提供了一個一次讀一行的方法readLine(),方便與對文本數(shù)據(jù)的獲取,當返回null時,表示讀到文件末尾。

    ? ? ? readLine()方法返回的時只返回回車符之前的數(shù)據(jù)內容,并不返回回車符,即讀取的內容中不包含任何行終止符(回車符和換行符)。

    --->readLine()方法原理:無論是讀一行,或讀取多個字符,其實最終都是在硬盤上一個一個讀取。所以最終使用的還是read方法一次讀一個

  • public class BufferedReaderDemo {
  • public static void main(String[] args) {
  • method();
  • }
  • public static void method(){
  • //創(chuàng)建一個讀取流對象
  • FileReader fr = null;
  • BufferedReader bfr = null;
  • try {
  • fr = new FileReader("buf.txt");
  • //為了提高效率。加入緩沖技術。將字符讀取流對象作為參數(shù)傳遞給緩沖對象的構造函數(shù)。
  • bfr = new BufferedReader(fr);
  • // char[] buf = new char[1024];
  • // bfr.read(buf);
  • // int len = 0;
  • // while((len = bfr.read(buf)) != -1){
  • // System.out.println(new String(buf,0,len));
  • // }
  • String line = null;
  • while((line = bfr.readLine()) != null){
  • System.out.println(line);
  • }
  • } catch (IOException e) {
  • e.printStackTrace();
  • }finally{
  • try {
  • bfr.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }

  • 三、通過緩沖技術提高效率復制文件:
  • public class CopyTextByBufTest {
  • //不處理異常,拋出去
  • public static void main(String[] args) throws IOException {
  • FileReader fr = new FileReader("buf.txt");
  • BufferedReader bufr = new BufferedReader(fr);
  • FileWriter fw = new FileWriter("buf_copy.txt");
  • BufferedWriter bufw = new BufferedWriter(fw);
  • String line = null;
  • while ((line = bufr.readLine()) != null) {
  • bufw.write(line);
  • bufw.newLine();
  • bufw.flush();
  • }
  • /*
  • * int ch = 0;
  • *
  • * while((ch=bufr.read())!=-1){
  • *
  • * bufw.write(ch); }
  • */
  • bufw.close();
  • bufr.close();
  • }
  • }
  • 處理異常try...catch
  • public class CopyByBuffer {
  • public static void main(String[] args) {
  • copyByBuf();
  • }
  • public static void copyByBuf() {
  • FileWriter fw = null;
  • FileReader fr = null;
  • BufferedWriter bfw = null;
  • BufferedReader bfr = null;
  • try {
  • fw = new FileWriter("C:\\buffertest.txt");//創(chuàng)建寫文件對象
  • fr = new FileReader("buffertest.txt");//創(chuàng)建讀文件對象
  • bfw = new BufferedWriter(fw);//使用緩沖區(qū)關聯(lián)讀寫對象
  • bfr = new BufferedReader(fr);
  • String line = null;
  • while ((line = bfr.readLine()) != null) {//通過讀一行的方式提高效率
  • bfw.write(line);
  • bfw.newLine();//換行,夸平臺
  • }
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • if (bfw != null) {
  • try {
  • bfw.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • if (bfr != null) {
  • try {
  • bfr.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }
  • }


  • 四、自定義緩沖區(qū)其實就是模擬一個BufferedReader.?* 分析:?* 緩沖區(qū)中無非就是封裝了一個數(shù)組,并對外提供了更多的方法對數(shù)組進行訪問。?其實這些方法最終操作的都是數(shù)組的角標。?*?* 緩沖的原理:?* 其實就是從源中獲取一批數(shù)據(jù)裝進緩沖區(qū)中。在從緩沖區(qū)中不斷的取出一個一個數(shù)據(jù)。?*?在此次取完后,在從源中繼續(xù)取一批數(shù)據(jù)進緩沖區(qū)。?當源中的數(shù)據(jù)取光時,用-1作為結束標記。
  • public class MyBufferedReader extends Reader {
  • private Reader r;
  • //定義一個數(shù)組作為緩沖區(qū)。
  • private char[] buf = new char[1024];
  • //定義一個指針用于操作這個數(shù)組中的元素。當操作到最后一個元素后,指針應該歸零。
  • private int pos = 0;
  • //定義一個計數(shù)器用于記錄緩沖區(qū)中的數(shù)據(jù)個數(shù)。 當該數(shù)據(jù)減到0,就從源中繼續(xù)獲取數(shù)據(jù)到緩沖區(qū)中。
  • private int count = 0;
  • MyBufferedReader(Reader r){
  • this.r = r;
  • }
  • /**
  • * 該方法從緩沖區(qū)中一次取一個字符。
  • * @return
  • * @throws IOException
  • */
  • /*
  • public int myRead() throws IOException{
  • //從源中獲取一批數(shù)據(jù)到緩沖區(qū)中。需要先做判斷,只有計數(shù)器為0時,才需要從源中獲取數(shù)據(jù)。
  • if(count==0){
  • count = r.read(buf); //這是在底層
  • if(count<0)//沒有了
  • return -1;
  • //每次獲取數(shù)據(jù)到緩沖區(qū)后,角標歸零(第一個read,底層)創(chuàng)建了一個數(shù)組。
  • pos = 0;
  • char ch = buf[pos];
  • // 然后調用一次(第二個)read,返回一個a,再調用返回b,角標取一個,count減一個
  • pos++;
  • count--;
  • return ch;
  • }
  • else if(count>0){//第二次調用的時候count就不為0了, 不需要count = r.read(buf)這一步了
  • char ch = buf[pos];
  • pos++;
  • count--;
  • return ch;
  • }*/


  • 優(yōu)化后
  • public int myRead() throws IOException{
  • if(count==0){
  • count = r.read(buf);
  • pos = 0;
  • }
  • if(count<0)
  • return -1;
  • char ch = buf[pos++];
  • count--;
  • return ch;
  • }
  • 五、模擬ReadLine
  • public String myReadLine() throws IOException{
  • // 定義一個臨時容器,原BufferedReader封裝的是字符數(shù)組,這里定義StringBuilder演示原理
  • StringBuilder sb = new StringBuilder();
  • int ch = 0;
  • while((ch = myRead())!=-1){
  • if(ch=='\r') //如是'\r'繼續(xù)往下讀
  • continue;
  • if(ch=='\n') //讀到'\n'就停止讀,然后將這些數(shù)據(jù)返回
  • return sb.toString();
  • //將從緩沖區(qū)中讀到的字符,存儲到緩存行數(shù)據(jù)的緩沖區(qū)中。
  • sb.append((char)ch);
  • }
  • if(sb.length()!=0) //最后沒有空格,說明有東西,返回,
  • //這里是防止最后一行沒有回車符的情況
  • return sb.toString();
  • return null;
  • }
  • public void myClose() throws IOException {
  • r.close();
  • }
  • @Override
  • public int read(char[] cbuf, int off, int len) throws IOException {
  • return 0;
  • }
  • @Override
  • public void close() throws IOException {
  • }
  • }
  • 運行 ReadLine
  • public class MyBufferedReaderDemo {
  • public static void main(String[] args) throws IOException {
  • FileReader fr = new FileReader("buf.txt");
  • MyBufferedReader bufr = new MyBufferedReader(fr);
  • String line = null;
  • while((line=bufr.myReadLine())!=null){
  • System.out.println(line);
  • }
  • bufr.myClose();
  • Collections.reverseOrder();
  • HashMap map = null;
  • map.values();
  • }
  • }
  • 六、LineNumberReader(功能增強的讀)

    在BufferedReader中有個直接的子類LineNumberReader,其中有特有的方法獲取和設置行號:

    setLineNumber()和getLineNumber()

  • public class LineNumberReaderDemo {
  • public static void main(String[] args) throws IOException {
  • FileReader fr = new FileReader("IO流_2.txt");
  • LineNumberReader lnr = new LineNumberReader(fr);
  • String line = null;
  • lnr.setLineNumber(100);// 默認是0
  • while ((line = lnr.readLine()) != null) {
  • System.out.println(lnr.getLineNumber() + ":" + line);
  • }
  • lnr.close();
  • }
  • }


  • 第四 ?裝飾設計模式

    裝飾設計模式: (buffer就是裝飾設計模式)?對一組對象的功能進行增強時,就可以使用該模式進行問題的解決。??裝飾和繼承都能實現(xiàn)一樣的特點:進行功能的擴展增強。?有什么區(qū)別呢??首先有一個繼承體系。Writer (抽取了一個寫的)?|--TextWriter?(隨便寫的):用于操作文本?|--MediaWriter:用于操作媒體。?想要對操作的動作進行效率的提高。按照面向對象,可以通過繼承對具體的進行功能的擴展。效率提高需要加入緩沖技術。?Writer?|--TextWriter:用于操作文本? |--BufferTextWriter:加入了緩沖技術的操作文本的對象。?|--MediaWriter:用于操作媒體。? |--BufferMediaWriter:到這里就哦了。但是這樣做好像并不理想。如果這個體系進行功能擴展,有多了流對象。那么這個流要提高效率,是不是也要產(chǎn)生子類呢?是。這時就會發(fā)現(xiàn)只為提高功能,進行的繼承,導致繼承體系越來越臃腫。不夠靈活。重新思考這個問題?既然加入的都是同一種技術--緩沖。前一種是讓緩沖和具體的對象相結合。可不可以將緩沖進行單獨的封裝,哪個對象需要緩沖就將哪個對象和緩沖關聯(lián)。
  • class Buffer {
  • Buffer(TextWriter w) // 要緩沖誰就加入進來
  • {
  • }
  • Buffer(MediaWirter w) // 要緩沖誰就加入進來
  • {
  • }
  • } // 但是這樣做,來新對象還得加入,比較麻煩
  • // 都能寫入,為了名字有意義,寫成BufferWriter
  • class BufferWriter extends Writer {
  • BufferWriter(Writer w) {
  • }
  • }

  • Writer?|--TextWriter:用于操作文本?|--MediaWriter:用于操作媒體。?|--BufferWriter:用于提高效率。
    ??裝飾比繼承靈活。?特點:裝飾類和被裝飾類都必須所屬同一個接口或者父類。?有個類想要增強,可以用裝飾設計模式,把被裝飾的類往里傳進來就可以

    第五 ?字節(jié)流

    一、概述:

    1、字節(jié)流和字符流的原理是相似的,而字符流是基于字節(jié)流的,字節(jié)流可以操作如媒體等其他數(shù)據(jù),如媒體(MP3,圖片,視頻)等

    2、由于媒體數(shù)據(jù)中都是以字節(jié)存儲的,所以,字節(jié)流對象可直接對媒體進行操作,而不用再進行刷流動作。

    3、InputStream ? ? ---> ?輸入流(讀) ?OutputStream ?---> ?輸出流(寫)

    4、為何不用進行刷流動作:因為字節(jié)流操作的是字節(jié),即數(shù)據(jù)的最小單位,不需要像字符流一樣要進行轉換為字節(jié)。可直接將字節(jié)寫入到指定文件中,但是需要在寫代碼的時候,如果有字符串,要將字符串轉為字節(jié)數(shù)組再進行操作。

    5、FileInputStream特有方法:int available() ---> ?返回數(shù)據(jù)字節(jié)的長度,包含終止符

    在定義字節(jié)數(shù)組長度的時候,可以用到這個方法:byte[] = new byte[fos.available()] ? (fos為字節(jié)流對象)但是,對于這個方法要慎用,如果字節(jié)過大,超過jvm所承受的大小(一般內存為64M),就會內存溢出。

    實例:
  • /
  • * 字節(jié)流操作
  • * InputStream OutputStream
  • *
  • */
  • public class FileStreamDemo {
  • public static void main(String[] args) {
  • // writeFile();
  • // readFile_1();
  • // readFile_2();
  • readFile_3();
  • }
  • /*
  • * 對字節(jié)流讀操作的第一種方式 通過read()方法讀取一個字節(jié)
  • */
  • public static void readFile_1() {
  • FileInputStream fis = null;// 定義字節(jié)輸入流
  • try {
  • fis = new FileInputStream("fos.txt");// 指定輸入流和文件關聯(lián)
  • int ch = 0;
  • while ((ch = fis.read()) != -1) {// 讀取操作
  • System.out.println((char) ch);
  • }
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • try {
  • if (fis != null)// 判空,提高程序的健壯性
  • fis.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • /*
  • * 對字節(jié)流讀操作的第二種方式 通過read(byte[])方法讀取字節(jié)數(shù)組
  • */
  • public static void readFile_2() {
  • FileInputStream fis = null;
  • try {
  • fis = new FileInputStream("fos.txt");
  • byte[] byf = new byte[1024];
  • int len = 0;
  • while ((len = fis.read(byf)) != -1) {
  • System.out.println(new String(byf, 0, len));
  • }
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • try {
  • if (fis != null)
  • fis.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • /*
  • * 對字節(jié)流讀操作的第三種方式 通過字節(jié)流的available()方法獲取到文件大小,定義一個大小剛剛好的數(shù)組,無需循環(huán) 但是,這種方式操作較大數(shù)據(jù)時容易內存溢出,所以要慎用 首選的還是定義1024的整數(shù)倍數(shù)組
  • */
  • public static void readFile_3() {
  • FileInputStream fis = null;
  • try {
  • fis = new FileInputStream("fos.txt");
  • // 通過這樣的方式定義一個剛剛好的數(shù)組
  • // 這種方法慎用,如果文件不大,可以用這個方法
  • byte[] byf = new byte[fis.available()];// fis.available()獲取文件大小
  • fis.read(byf);
  • System.out.println(new String(byf));
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • try {
  • fis.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • /*
  • * 對字節(jié)流進行寫操作
  • */
  • public static void writeFile() {
  • FileOutputStream fos = null;
  • try {
  • fos = new FileOutputStream("fos.txt");//定義字節(jié)寫出流和文件關聯(lián)
  • fos.write("abcds".getBytes());// str.getBytes()將String轉化成字節(jié)數(shù)組
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • if (fos != null)
  • try {
  • fos.close();// 因為字節(jié)流沒有用到緩沖區(qū),所以不需要刷新,但必須關閉資源
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }
  • 二、通過字節(jié)流復制媒體文件

    思路:

    1、用字節(jié)流讀取流對象和媒體文件相關聯(lián)

    2、用字節(jié)寫入流對象,創(chuàng)建一個媒體文件,用于存儲獲取到的媒體文件數(shù)據(jù)

    3、通過循環(huán)讀寫,完成數(shù)據(jù)的存儲

    4、關閉資源

  • * 通過字節(jié)流拷貝圖片
  • */
  • public class CopyPicture {
  • public static void main(String[] args) {
  • copyPic();
  • }
  • public static void copyPic() {
  • FileInputStream fis = null;
  • FileOutputStream fos = null;
  • try {
  • fis = new FileInputStream("1.jpg");
  • fos = new FileOutputStream("C:\\1.jpg");
  • byte[] byf = new byte[1024];
  • int len = 0;
  • while ((len = fis.read(byf)) != -1) {// 將數(shù)據(jù)讀取到數(shù)組中
  • fos.write(byf, 0, len);// 寫入數(shù)組中的有效數(shù)據(jù)
  • }
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • // 有多個流不能一起關閉,要分別關閉
  • if (fis != null) {
  • try {
  • fis.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • if (fos != null) {
  • try {
  • fos.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }
  • }
  • // 千萬不要用,效率沒有!
  • public static void copy_4() throws IOException {
  • FileInputStream fis = new FileInputStream("c:\\0.mp3");
  • FileOutputStream fos = new FileOutputStream("c:\\4.mp3");
  • int ch = 0;
  • while((ch =fis.read())!=-1){
  • fos.write(ch);
  • }
  • fos.close();
  • fis.close();
  • }
  • //不建議。
  • public static void copy_3() throws IOException {
  • FileInputStream fis = new FileInputStream("c:\\0.mp3");
  • FileOutputStream fos = new FileOutputStream("c:\\3.mp3");
  • byte[] buf = new byte[fis.available()];
  • fis.read(buf);
  • fos.write(buf);
  • fos.close();
  • fis.close();
  • }
  • //提高效率
  • public static void copy_2() throws IOException {
  • FileInputStream fis = new FileInputStream("c:\\0.mp3");
  • BufferedInputStream bufis = new BufferedInputStream(fis);
  • FileOutputStream fos = new FileOutputStream("c:\\2.mp3");
  • BufferedOutputStream bufos = new BufferedOutputStream(fos);
  • int ch = 0;
  • while((ch=bufis.read())!=-1){
  • bufos.write(ch);
  • }
  • bufos.close();
  • bufis.close();
  • }
  • 三、字節(jié)流緩沖區(qū)

    1、緩沖區(qū)的出現(xiàn)無非就是提高了流的讀寫效率,當然也就是因為這樣,所以緩沖區(qū)的使用頻率也是相當高的,所以要做必要性的掌握。

    2、字節(jié)流緩沖區(qū)讀寫的特點:

    這里沒有什么特殊的讀寫方法,就是read()讀一個字節(jié),read(byte[])讀數(shù)組的方法。寫write(int?b)寫一個自己,write(byte[])寫數(shù)組的方法。

    注:需要注意個地方,write方法只寫出二進制的最后八位。

    原理:將數(shù)據(jù)拷貝一部分,讀取一部分,循環(huán),直到數(shù)據(jù)全部讀取完畢。

    1)先從數(shù)據(jù)中抓取固定數(shù)組長度的字節(jié),存入定義的數(shù)組中,再通過然后再通過read()方法讀取數(shù)組中的元素,存入緩沖區(qū)

    2)循環(huán)這個動作,知道最后取出一組數(shù)據(jù)存入數(shù)組,可能數(shù)組并未填滿,同樣也取出包含的元素

    3)每次取出的時候,都有一個指針在移動,取到數(shù)組結尾就自動回到數(shù)組頭部,這樣指針在自增

    4)取出的時候,數(shù)組中的元素再減少,取出一個,就減少一個,直到減到0即數(shù)組取完

    5)到了文件的結尾處,存入最后一組數(shù)據(jù),當取完數(shù)組中的元素,就會減少到0,這是全部數(shù)據(jù)就取完了

    3、自定義字節(jié)緩沖區(qū):
  • * 自定義字節(jié)流緩沖區(qū)
  • */
  • public class MyBufferedInputStream {
  • private InputStream in;
  • private byte[] buf = new byte[1024];
  • private int pos;// 定義數(shù)組的指針
  • private int count;// 定義計數(shù)器
  • MyBufferedInputStream(InputStream in) {
  • this.in = in;
  • }
  • // 一次讀一個字節(jié),從緩沖區(qū)(數(shù)組)中取得
  • public int myRead() throws IOException {
  • // 通過in對象讀取數(shù)據(jù)并存放在buf數(shù)組中
  • if (count == 0) {
  • count = in.read(buf);
  • if (count < 0) {
  • return -1;
  • }
  • pos = 0;
  • byte b = buf[pos];
  • count--;
  • pos++;
  • return b & 255;// &255是因為存放的是二進制,也就是可能前八位是11111111,提升為int還是-1,就直接return了,
  • // &255就是讓前面補0
  • /*
  • * 11111111 11111111 11111111 11111111
  • * &00000000 00000000 00000000 11111111
  • * ------------------------------------
  • * 00000000 00000000 00000000 11111111
  • */
  • }else if(count>0){
  • byte b = buf[pos];
  • count--;
  • pos++;
  • return b&255;//&0xff
  • }
  • return -1;
  • }
  • public void myClose() throws IOException{
  • in.close();
  • }
  • }
  • 注:取出的是byte型,返回的是int型,這里存在提升的動作,
    當byte中的八位全為1的時候是byte的-1,提升為int類型,就變?yōu)閕nt型的-1,為-1時程序就停止循環(huán)了,read循環(huán)條件就結束了,變?yōu)?1的原因是由于在提升時,將byte的八位前都補的是1,即32位的數(shù)都是1,即為int型的-1了。如何保證提升后的最后八位仍為1呢?就需要將前24位補0,就可以保留原字節(jié)數(shù)據(jù)不變,又可以避免轉為int型出現(xiàn)-1的情況;
    那么要如何做呢?
    這就需要將提升為int的數(shù)據(jù)和前24位為0,后八位仍為原字節(jié)數(shù)據(jù)的這個值做與運算。即和255做與運算即可。說到了這里應該也明白了為什么Read方法返回值為int類型了。


    第六 ?轉換流

    轉換流:轉換流可以實現(xiàn)字節(jié)數(shù)據(jù)和字符數(shù)據(jù)的相互轉換方便與操作,而且在轉換的時候可以指定編碼,這也是該流最具特色的地方。:

    InputStreamReader 是字節(jié)流通向字符流的橋梁

    OutputStreamWriter 是字符流通向字節(jié)流的橋梁


    轉換流的子類和轉換流的區(qū)別?InputStreamReader ? 字節(jié)-->字符??|--FileReader : 字節(jié)流+本地默認碼表。OutputStreamWriter ?字符-->字節(jié)?|--FileWriter?
    什么時候使用轉換流呢?1,源或者目的對應的設備是字節(jié)流,但是操作的卻是文本數(shù)據(jù),可以使用轉換作為橋梁。提高對文本操作的便捷。2,一旦操作文本涉及到具體的指定編碼表時,必須使用轉換流 。BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));

  • ? ? ? //獲取鍵盤錄入對象??
  • ?????????InputStream?in?=?System.in;??
  • ??????????
  • ?????????//將字節(jié)流對象轉換成字符流對象??
  • ?????????InputStreamReader?isr?=?new?InputStreamReader(in);??
  • ??????????
  • ?????????//將字符流對象用緩沖技術高效處理??
  • ?????????BufferedReader?bufr?=?new?BufferedReader(isr);
  • ? ? ? ? ?//?鍵盤錄入最常見的寫法??
  • ? ? ? ? ?BufferedReader?bufr?=?new?BufferedReader(new ?InputStreamReader(System.in)); ?


  • 字符流轉字節(jié)流:
  • ? ? ? ? //?操作輸出??
  • ????????//?獲取輸出流??
  • ?????????OutputStream?out?=?System.out;??
  • ?????????//將字符流轉換成字節(jié)流,OutputStreamWriter字符流通向字節(jié)流的橋梁??
  • ?????????OutputStreamWriter?osw?=?new?OutputStreamWriter(out);??
  • ?????????BufferedWriter?bfw?=?new?BufferedWriter(osw);//高效緩沖區(qū)

  • 獲取鍵盤輸入:鍵盤輸入都是字節(jié),所以用到字節(jié)流與標準輸入流相關聯(lián)就可以把輸入的數(shù)據(jù)獲取到流中,以達到數(shù)據(jù)的操作效果。
  • * 獲取鍵盤錄入
  • public class ReadIn {
  • public static void main(String[] args) {
  • // method_1();
  • // method_2();
  • InputStreamReaderDemo();
  • }
  • /*
  • * 獲取鍵盤錄入
  • */
  • public static void method_1() {
  • InputStream in = System.in;// 定義輸入流與鍵盤輸入流相關聯(lián)
  • int ch = 0;
  • try {
  • while ((ch = in.read()) != -1) {
  • System.out.println(ch);
  • }
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • /*
  • * 需求:通過鍵盤錄入數(shù)據(jù)。 當錄入一行數(shù)據(jù)后,就將該行數(shù)據(jù)進行打印。 如果錄入的數(shù)據(jù)是over,那么停止錄入。
  • * 1,因為鍵盤錄入只讀取一個字節(jié),要判斷是否是over,需要將讀取到的字節(jié)拼成字符串。
  • * 2,那就需要一個容器。StringBuilder.
  • * 3,在用戶回車之前將錄入的數(shù)據(jù)變成字符串判斷即可。
  • */
  • public static void method_2() {
  • InputStream in = System.in;
  • StringBuilder sb = new StringBuilder();// 定義一個臨時容器
  • while (true) {
  • int ch = 0;
  • try {
  • ch = in.read();
  • if (ch == '\r')// windows中換行符為\r\n
  • continue;
  • if (ch == '\n') {
  • String s = sb.toString();// 當讀到一行的結束標記時,把改行數(shù)據(jù)變成字符串
  • if ("over".equals(s))
  • break;
  • System.out.println(s.toUpperCase()); //變成大寫
  • sb.delete(0, sb.length());// 清空容器 ,不清空會將上次輸入的和這次輸入的都輸出
  • } else {
  • sb.append((char) ch); //將讀取到的字節(jié)存儲到StringBuilder中。
  • }
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • // **************************************************************************
  • /*
  • * 通過上面錄入一行數(shù)據(jù),發(fā)現(xiàn)其方法類似于readLine方法 但是readLine方法是字符流緩沖區(qū)的方法,所以需要把字節(jié)流轉換成字符流進行操作
  • * 需要用到InputStreamReader方法進行轉換,InputStreamReader字節(jié)通向字符的橋梁
  • *
  • * 轉換流
  • */
  • public static void InputStreamReaderDemo() {
  • BufferedReader bufr = null;
  • try {
  • // 源為文件
  • bufr = new BufferedReader(new InputStreamReader(
  • new FileInputStream("buf.txt")));
  • } catch (FileNotFoundException e2) {
  • e2.printStackTrace();
  • }
  • // 操作輸出
  • // 目的地是控制臺
  • BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(
  • System.out));
  • // 目的地是文件
  • // BufferedWriter bfw = null;
  • // try {
  • // bfw = new BufferedWriter(new OutputStreamWriter(new
  • // FileOutputStream("out.txt")));
  • // } catch (FileNotFoundException e1) {
  • // e1.printStackTrace();
  • // }
  • String line = null;
  • try {
  • while ((line = bufr.readLine()) != null) {
  • if ("over".equals(line)) {
  • break;
  • }
  • bfw.write(line.toUpperCase());
  • bfw.newLine();// 換行
  • bfw.flush();// 數(shù)據(jù)存放在緩沖區(qū),所以需要刷新
  • }
  • } catch (IOException e) {
  • e.printStackTrace();
  • } finally {
  • try {
  • bufr.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • }
  • 不處理異常
  • public class TransStreamDemo2 {
  • public static void main(String[] args) throws IOException {
  • /*
  • * 1,需求:將鍵盤錄入的數(shù)據(jù)寫入到一個文件中。
  • *
  • * 2,需求:將一個文本文件內容顯示在控制臺上。
  • *
  • * 3,需求:將一個文件文件中的內容復制到的另一個文件中。
  • */
  • BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
  • BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
  • String line = null;
  • while((line=bufr.readLine())!=null){
  • if("over".equals(line))
  • break;
  • bufw.write(line.toUpperCase()); //變成大寫
  • bufw.newLine();
  • bufw.flush();
  • }
  • }
  • }


  • 第七 ?流的操作規(guī)律

    之所以要弄清楚這個規(guī)律,是因為流對象太多,開發(fā)時不知道用哪個對象合適。想要知道開發(fā)時用到哪些對象。只要通過四個明確即可。1,明確源和目的(匯)?源:InputStream ?Reader?目的:OutputStream ?Writer2,明確數(shù)據(jù)是否是純文本數(shù)據(jù)。?源:是純文本:Reader? 否:InputStream?目的:是純文本 Writer? 否:OutputStream??到這里,就可以明確需求中具體要使用哪個體系。?3,明確具體的設備。?源設備:? 硬盤:File? 鍵盤:System.in? 內存:數(shù)組? 網(wǎng)絡:Socket流??目的設備:? 硬盤:File? 控制臺:System.out? 內存:數(shù)組? 網(wǎng)絡:Socket流4,是否需要其他額外功能。?1,是否需要高效(緩沖區(qū));? 是,就加上buffer.?2,轉換。?需求1:復制一個文本文件。?1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本?? 是!? 源:Reader? 目的:Writer??3,明確具體設備。? 源:? ?硬盤:File? 目的:? ?硬盤:File?? FileReader fr = new FileReader("a.txt");? FileWriter fw = new FileWriter("b.txt");??4,需要額外功能嗎?? 需要,需要高效。? BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));? BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));?================================================需求2:讀取鍵盤錄入信息,并寫入到一個文件中。??1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本呢?? 是,? 源:Reader? 目的:Writer?3,明確設備? 源:? ?鍵盤。System.in? 目的:? ?硬盤。File? ?? InputStream in = System.in;? FileWriter fw = new FileWriter("b.txt");? 這樣做可以完成,但是麻煩。將讀取的字節(jié)數(shù)據(jù)轉成字符串。再由字符流操作。?4,需要額外功能嗎?? 需要。轉換。 將字節(jié)流轉成字符流。因為名確的源是Reader,這樣操作文本數(shù)據(jù)做便捷。? ?所以要將已有的字節(jié)流轉成字符流。使用字節(jié)-->字符 。InputStreamReader? InputStreamReader isr = new InputStreamReader(System.in);? FileWriter fw = new FileWriter("b.txt");?? 還需要功能嗎?? 需要:想高效。? BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));? BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));?? ??===================================================?需求3:將一個文本文件數(shù)據(jù)顯示在控制臺上。?1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本呢?? 是,? 源:Reader? 目的:Writer?3,明確具體設備? 源:? ?硬盤:File? 目的:? ?控制臺:System.out? ?? FileReader fr = new FileReader("a.txt");? OutputStream out = System.out;//PrintStream?4,需要額外功能嗎?? 需要,轉換。? FileReader fr= new FileReader("a.txt");? OutputStreamWriter osw = new OutputStreamWriter(System.out);? 需要,高效。? BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));? BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));?================================================================需求4:讀取鍵盤錄入數(shù)據(jù),顯示在控制臺上。?1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本呢?? 是,? 源:Reader? 目的:Writer?3,明確設備。? 源:? ?鍵盤:System.in? 目的:? ?控制臺:System.out?? InputStream in = System.in;? OutputStream out = System.out;??4,明確額外功能?? 需要轉換,因為都是字節(jié)流,但是操作的卻是文本數(shù)據(jù)。? 所以使用字符流操作起來更為便捷。? InputStreamReader isr = new InputStreamReader(System.in);? OutputStreamWriter osw = new OutputStreamWriter(System.out);?? 為了將其高效。? BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));? BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));??============================================================5,將一個中文字符串數(shù)據(jù)按照指定的編碼表寫入到一個文本文件中.??1,目的。OutputStream,Writer?2,是純文本,Writer。?3,設備:硬盤File?FileWriter fw = new FileWriter("a.txt");?fw.write("你好");??注意:既然需求中已經(jīng)明確了指定編碼表的動作。?那就不可以使用FileWriter,因為FileWriter內部是使用默認的本地碼表。?只能使用其父類。OutputStreamWriter.?OutputStreamWriter接收一個字節(jié)輸出流對象,既然是操作文件,那么該對象應該是FileOutputStream??OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName(編碼));??需要高效嗎??BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
    ??演示:將一個中文字符串數(shù)據(jù)按照指定的編碼表寫入到一個文本文件中.?寫:
  • public static void writeText_2() throws IOException {
  • OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
  • "gbk_3.txt"), "GBK");
  • // OutputStreamWriter osw = new OutputStreamWriter(new
  • // FileOutputStream("gbk_3.txt"),"GBK");
  • // FileWriter fw = new FileWriter("gbk_1.txt");
  • /*
  • * 這兩句代碼的功能是等同的。 FileWriter:其實就是轉換流指定了本機默認碼表的體現(xiàn)。而且這個轉換流的子類對象,可以方便操作文本文件。
  • * 簡單說:操作文件的字節(jié)流+本機默認的編碼表。 這是按照默認碼表來操作文件的便捷類。
  • *
  • * 如果操作文本文件需要明確具體的編碼。FileWriter就不行了。必須用轉換流
  • */
  • osw.write("你好");
  • osw.close();
  • }
  • public static void writeText_3() throws IOException {
  • OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
  • "u8_1.txt"), "UTF-8");
  • osw.write("你好");
  • osw.close();
  • }

  • 讀:
  • public static void readText_1() throws IOException {
  • FileReader fr = new FileReader("gbk_1.txt");
  • char[] buf = new char[10];
  • int len = fr.read(buf);
  • String str = new String(buf,0,len);
  • System.out.println(str);
  • fr.close();
  • }
  • //用utf-8讀默認的編碼文件
  • public static void readText_2() throws IOException, FileNotFoundException {
  • InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk_1.txt"),"utf-8");
  • char[] buf = new char[10];
  • int len = isr.read(buf);
  • String str = new String(buf,0,len);
  • System.out.println(str);
  • isr.close();
  • }
  • }
  • }


  • ?

    來自為知筆記(Wiz)

    轉載于:https://www.cnblogs.com/sixrain/p/4912372.html

    總結

    以上是生活随笔為你收集整理的14:IO之字符字节流的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。