在JavaSe的基礎課程當中,可以說流是1個非常重要的概念,并且在Hadoop中得到了廣泛的利用,本篇博客將圍繞流進行深入的詳解。
(1)JavaSe中流的相干概念
1、流的定義
①在Java當中,若1個類專門用于數據傳輸,則這個類稱為流
②流就是程序和裝備之間嫁接以來的1根用于數據傳輸的管道,這個裝備可以是本地硬盤,可以是內存條,也能夠是網絡所關聯的另外1臺計算機等等,其中不同管道上有不同的按鈕,按下不同的按鈕相當于調用不同的方法,這根帶按鈕的用于數據傳輸的管道就是流,即流就是1根管道
③流1定是類,但類不1定是流
2、流的分類
依照數據流的方向不同分為輸入流與輸出流、依照處理數據單位的不同分為字節流與字符流、依照功能的不同分為原始流與包裹流。
輸入流與輸出流:所謂輸入流就是通過輸入管道從指定的裝備當中讀取數據,例如鍵盤。所謂輸出流就是通過輸出管道向指定的裝備當中寫入數據,例如顯示器。
字節流與字符流:字節流處理數據的單位是1個字節,字符流處理數據的單位是1個字符,在Java當中1個字符相當于兩個字節。
原始流:可以從1個特定的裝備即數據 源中讀寫數據的流,就像是1條單1的管道接到水龍頭上開始放水。
包裹流:所謂包裹流就是由于原始流的功能太簡單了,對原始流進行1定的加工處理—-在原始流的基礎上套1個功能比較強大的管子,這個管子稱為包裹流。包裹流類似于在1條已存在的管子套上另外1根管子。
原始流與包裹流的關鍵區分在于能不能直接連接到裝備。
3、4大基本抽象流
所謂4大基本抽象流就是4大基本抽象類,4大基本抽象流包括字節流和字符流,其中字節流包括InputStream和OutPutstream,字符流包括Reader和Writer,并且凡是以Stream結尾的都是字節流。
字節流與字符流的方法1模1樣,僅僅是處理數據的單位不1樣;InputStream是所有字節輸入流的父類、OutputStream是所有字節輸出流的父類;Reader是所有字符輸入流的父類,Writer是所有字符輸出流的父類。
4、IO包中經常使用的流
文件流(原始流):
FileInputStream FileReader
FileOutputStream FileWriter
輸出流(原始流):
PrintStream
緩沖流(包裹流):
BufferedInputStream BufferedReader
BufferedOutputStream BufferedWriter
轉換流(包裹流):
InputStreamReader
OutputStreamWriter
數據流(包裹流):
DatainputStream
DataOutputStream
5、文件流、輸出流、緩沖流、轉換流、數據流的相干作用
文件流:Java中的文件流可以將1個文件的內容按字節或字符為單位來進行讀寫、復制
輸出流:PrintStream在OutputStream基礎之上提供了增強的功能,可以將基本類型數據格化后的字符串進行輸出
緩沖流:緩沖流就是帶有緩沖區的輸入輸出流,帶緩沖區的流比不帶緩沖區的流運行速度要快,由于此時此刻不是讀1個寫1個,而是讀取完以后先放到緩沖區里面,在1次性寫到指定的裝備當中
轉換流:InputStreamReader的作用是將輸入字節流轉換成字符流
OutputStreamWriter的作用是將輸出字節流轉換成字符流
數據流:Java中的數據流能夠以1種與機器無關的方式,直接從底層字節輸入流當中讀取基本類型數據或直接將基本類型數據寫到字節輸出流當中,即數據流可以將基本類型數據的2進制直接讀入或寫出
6、簡述字節流與字符流的區分
1>字節流可以處理所有格式的文件,但是帶有漢字的文本通過字節流輸出到顯示器上時會出現亂碼的現象,但是若要完成的是文本文件的復制則不會出現亂碼的現象—即字節流可以完成文本文件的拷貝
但是Hadoop中的IOUtils工具類解決了字節流的這個缺點
2>字符流只能處理文本格式的文件,不能處理非文本格式的文件,由于非文本格式的文件本身就不是由1個1個字符組成的,因此若要當作1個1個字符來解讀肯定會出錯
3>在實際項目當中字節流是廣泛使用的
(2)JavaSe中流的具體利用—-結合Hadoop中的Api(IOUtils)
IOUtils是Hadoop自己提供的工具類,在編程的進程中用的非常方便———import org.apache.hadoop.io.IOUtils,下面將結合具體的實例進行說明。
實際開發進程中提倡2點:
1>盡可能用字節流處理問題
2>盡可能用Hadoop中的org.apache.hadoop.io.IOUtils工具類解決問題,由于簡單
實例1:讀取1個文件的內容,并將其輸出到顯示器上
方法①
package JavaSe;
import java.io.BufferedReader;
import java.io.FileReader;
public class App1
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new FileReader("C:\\file.txt"));
int i = fr.read();
while(-1!=i)//⑴表示讀取到了文件的末尾
{
System.out.print((char)i);
i = fr.read();
}
}
}
//運行結果:
/*
Sometimes your plans don’t work out because God has better ones.
毅力和耐性在某種程度上將決定1個人會成為何樣的人。
*/
方法②
package JavaSe;
import java.io.BufferedReader;
import java.io.FileReader;
public class App1
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new FileReader("C:\\file.txt"));
char[] buf = new char[1024];
int len = fr.read(buf);//從fr所關聯的文件當中讀取數據并寄存在數組buf中
System.out.println(new String(buf,0,len));
}
}
//運行結果:
/*
Sometimes your plans don’t work out because God has better ones.
毅力和耐性在某種程度上將決定1個人會成為何樣的人。
*/
方法③利用Hadoop自帶的工具類:IOUtils(解決了字節流將漢字文本輸出到顯示器上時出現亂碼的缺點),并且相比于JavaSe中IO的方法更簡單
package JavaSe;
import java.io.FileInputStream;
import org.apache.hadoop.io.IOUtils;
public class App1
{
public static void main(String[] args) throws Exception
{
FileInputStream fr = new FileInputStream("C:\\file.txt");
IOUtils.copyBytes(fr,System.out,1024,true);
}
}
//運行結果:
/*
Sometimes your plans don’t work out because God has better ones.
毅力和耐性在某種程度上將決定1個人會成為何樣的人。
*/
實例2:編程實現文件的復制—將C盤下的file.txt文本文件復制到D盤下的file2.txt文本文件中
方法①
package JavaSe;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class App2
{
public static void main(String[] args) throws Exception
{
BufferedInputStream fr = new BufferedInputStream(new FileInputStream("C:\\file.txt"));
BufferedOutputStream fw = new BufferedOutputStream(new FileOutputStream("D:\\file2.txt"));
int i = fr.read();
while(-1!=i)
{
fw.write(i);
i = fr.read();
}
fw.flush();
fr.close();
fw.close();
}
}
方法②
package JavaSe;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class App2
{
public static void main(String[] args) throws Exception
{
BufferedInputStream fr = new BufferedInputStream(new FileInputStream("C:\\file.txt"));
BufferedOutputStream fw = new BufferedOutputStream(new FileOutputStream("D:\\file2.txt"));
byte[] buf = new byte[1024];
int i = fr.read(buf);
fw.write(buf,0,i);
fw.flush();
fw.close();
fr.close();
}
}
方法③利用Hadoop自帶的工具類:org.apache.hadoop.io.IOUtils,相比于JavaSe中IO的方法更簡單
package JavaSe;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.PrintStream;
import org.apache.hadoop.io.IOUtils;
public class App2
{
public static void main(String[] args) throws Exception
{
BufferedInputStream fr = new BufferedInputStream(new FileInputStream("C:\\file.txt"));
System.setOut(new PrintStream("D:\\file2.txt"));//對標準輸出流進行重定向
IOUtils.copyBytes(fr,System.out,1024,true);
}
}
實例3:利用BufferReader中的readLine()方法和BufferedWriter中的writeLine()方法完成文本文件的復制—-項目中常做這個事情
package JavaSe;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class App3
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new FileReader("C:\\file.txt"));
BufferedWriter fw = new BufferedWriter(new FileWriter("D:\\file2.txt"));
String str = fr.readLine();
while(str!=null)
{
fw.write(str);
fw.newLine();
str = fr.readLine();
}
fw.flush();
fr.close();
fw.close();
}
}
實例4:編程實現將long基本類型數據寫入byte數組,然后再從byte數組中把該數據讀出來—-這是Socket編程中常常要完成的任務
方法①
package JavaSe;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Scanner;
public class App4
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
long i = scanner.nextLong();
ByteArrayOutputStream array = new ByteArrayOutputStream();//內核為字節數組
DataOutputStream fw = new DataOutputStream(array);
fw.writeLong(i);//將長整型變量i寫到字節數組中
byte[] byteArray = array.toByteArray();//拷貝array內核字節數組的內容
ByteArrayInputStream bytearray = new ByteArrayInputStream(byteArray);
DataInputStream fr = new DataInputStream(bytearray);
long j = fr.readLong();
System.out.println(j);
}
}
//運行結果:
/*
65
65
* */
方法②
package JavaSe;
import java.util.Scanner;
public class App4
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
long i = scanner.nextLong();
String str = i +"";
byte[] bytes = str.getBytes();//將長整型變量i間接存到數組中
System.out.println(new String(bytes));
}
}
//運行結果:
/*
65
65
* */
注:本例子不合適用Hadoop自帶的工具類:org.apache.hadoop.io.IOUtils進行解決
實例5:利用數據流完成1個基本類型數據序列化與反序列化的實例
package JavaSe;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Scanner;
public class App5
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
int j = scanner.nextInt();
DataOutputStream fw = new DataOutputStream(new FileOutputStream("C:\\file2.txt"));
fw.writeInt(i);
fw.writeInt(j);
DataInputStream fr = new DataInputStream(new FileInputStream("C:\\file2.txt"));
int i2 = fr.readInt();
int j2 = fr.readInt();
System.out.println(i);
System.out.println(j);
}
}
//運行結果:
/*
65
56
65
56
* */
序列化與反序列的注意事項:
1>所謂序列化就是將對象以2進制情勢寫到字節輸出流當中,所謂反序列化就是將對象從字節輸入流當中讀取出來
2>序列化與反序列化的順序要保持相同:哪一個數據先寫進流管道里,哪一個數據就先從流管道里讀出來
3>Java中的數據流是將基本類型數據的2進制代碼寫到文本文件中,而Java中的輸出流PrintStream是將基本類型數據的字符串寫到文本文件中/font>
下面為示例結果:
當我們將上面程序中的file2.txt文件打開以后結果以下:
其中:
00 00 00 41為65的16進制,00 00 00 38為56的16進制
實例5:編程實現將鍵盤輸入的字符組成字符串直接賦給String對象
方法①
package JavaSe;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class App5
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new InputStreamReader(System.in));//將鍵盤輸入的字節流轉化為字符流
String str = fr.readLine();
System.out.println(str);
}
}
//運行結果:
/*
數據分析玩家shujufenxiwanjia
數據分析玩家shujufenxiwanjia
*/
方法②
package JavaSe;
import java.util.Scanner;
public class App5
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
System.out.println(str);
}
}
//運行結果:
/*
數據分析玩家shujufenxiwanjia
數據分析玩家shujufenxiwanjia
*/
實例6:標準輸入輸出的重定向:編程實現將鍵盤輸入的數據輸入file1.txt文件中,如果輸入有誤,則將出錯信息輸出到B文件中
所用知識點:
1>相干api以下圖所示:
2>Java異常中的e.printStackTrace()方法默許是將出錯信息輸出到System.err所關聯的裝備中
package JavaSe;
import java.io.PrintStream;
import java.util.Scanner;
public class App6
{
public static void main(String[] args) throws Exception
{
System.setOut(new PrintStream("C:\\file1.txt"));//重定向輸出
System.setErr(new PrintStream("C:\\file2.txt"));//重定向毛病輸出
while(true)
{
Scanner scanner = new Scanner(System.in);
try
{
int i = scanner.nextInt();
System.out.println(i);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
運行終了后:
file1.txt文本文件中的內容為:
23
56
file2.txt文本文件中的內容為:
java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at JavaSe.App1.main(App1.java:19)
針對JavaSe基礎編程當中流的用法就寫到這里,如有問題,歡迎留言指正!
上一篇 MongoDB實用教程
下一篇 PhotoView 源碼解讀