【Java基礎之五】Java中IO詳解
1.Java IO簡介
可能學過計算機組裝與維修的同學都知道I/O裝置,翻譯過來也就是Input/Output(輸入輸出裝置),在硬體中鍵盤、滑鼠 屬於 輸入裝置,顯示器、印表機等屬於輸出裝置,這裡輸入輸出參考物是計算機本身。
java.io包從巨集觀上來理解和硬體有些相同,Java中IO是以流為基礎進行輸入輸出的,所有資料被序列化寫入輸出流,或者從輸入流讀入。
流是一種有順序的,有起點和終點的位元組集合,是對資料傳輸的總成或抽象。即資料在兩裝置之間的傳輸稱之為流,流的本質是資料傳輸,根據資料傳輸的特性將流抽象為各種類,方便更直觀的進行資料操作。
2.Java IO使用場景
Java的IO包主要關注的是從原始資料來源的讀取以及輸出原始資料到目標媒介。以下是最典型的資料來源和目標媒介:
1.檔案
2.管道
3.網路連線
4.記憶體快取
5.System.in, System.out, System.error(注:Java標準輸入、輸出、錯誤輸出)
2.1 Java IO 的一般使用原則
2.1.1 按資料來源(去向)分類
1 、是檔案: FileInputStream, FileOutputStream, ( 位元組流 )FileReader, FileWriter( 字元 )
2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 位元組流 )
3 、是 Char[]: CharArrayReader, CharArrayWriter( 字元流 )
4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 位元組流 )StringReader, StringWriter( 字元流 )
5 、網路資料流: InputStream, OutputStream,( 位元組流 ) Reader, Writer( 字元流 )
2.1.2 按是否格式化輸出分
1 、要格式化輸出: PrintStream, PrintWriter
2.1.3 按是否要緩衝分
1 、要緩衝: BufferedInputStream, BufferedOutputStream,( 位元組流 ) BufferedReader, BufferedWriter( 字元流 )
2.1.4 按資料格式分
1 、二進位制格式(只要不能確定是純文字的) : InputStream, OutputStream 及其所有帶 Stream 結束的子類
2 、純文字格式(含純英文與漢字或其他編碼方式); Reader, Writer 及其所有帶 Reader, Writer 的子類
2.1.5 按輸入輸出分
1 、輸入: Reader, InputStream 型別的子類
2 、輸出: Writer, OutputStream 型別的子類
2.1.6 特殊需要
1 、從 Stream 到 Reader,Writer 的轉換類: InputStreamReader, OutputStreamWriter
2 、物件輸入輸出: ObjectInputStream, ObjectOutputStream
3 、程序間通訊: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4 、合併輸入: SequenceInputStream
5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
決定使用哪個類以及它的構造程序的一般準則如下(不考慮特殊需要):
首先,考慮最原始的資料格式是什麼: 原則2.1.4
第二,是輸入還是輸出:原則2.1.5
第三,是否需要轉換流:原則2.1.6第1點
第四,資料來源(去向)是什麼:原則2.1.1
第五,是否要緩衝:原則2.1.3 (特別註明:一定要注意的是 readLine() 是否有定義,有什麼比 read, write 更特殊的輸入或輸出方法)
第六,是否要格式化輸出:原則2.1.2
3.Java IO分類
按資料處理方式分 :位元組流 & 字元流
按資料起點終點分 :輸入流 & 輸出流
關於類的分類圖如下:
這是Java IO比較基本的一些處理流。
4.Java IO舉例
4.1 檔案
Demo:
package com.shuidi.iotest;
import java.io.File;
public class FileTest {
public static void main(String[] args) {
createFile();
}
/**
* File test
*/
public static void createFile() {
File f = new File("create.txt");
try{
f.createNewFile();
System.out.println("該分割槽大小"+f.getTotalSpace()/(1024*1024*1024)+"G"); //返回由此抽象路徑名錶示的檔案或目錄的名稱。
f.mkdirs(); //建立此抽象路徑名指定的目錄,包括所有必需但不存在的父目錄。
//f.delete(); // 刪除此抽象路徑名錶示的檔案或目錄
System.out.println("檔名 "+f.getName()); // 返回由此抽象路徑名錶示的檔案或目錄的名稱。
System.out.println("檔案父目錄字串 "+f.getParent());// 返回此抽象路徑名父目錄的路徑名字串;如果此路徑名沒有指定父目錄,則返回 null。
} catch (Exception e) {
e.printStackTrace();
}
}
}
輸出:
該分割槽大小131G
檔名 create.txt
檔案父目錄字串 null
4.2 位元組流
4.2.1 輸入流InputStream
package com.shuidi.iotest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileInputStreamTest {
public static void main(String[] args) {
int count=0; //統計檔案位元組長度
InputStream streamReader = null; //檔案輸入流
try {
streamReader = new FileInputStream(new File("FileInoutStreamTest.jpg"));
System.out.println("---長度是: "+ streamReader.available() +" 位元組");
byte[] b = new byte[1024];
int temp;
while( (temp = streamReader.read(b)) != -1) { //讀取檔案位元組,並遞增指標到下一個位元組
if (temp != 1024 && temp != -1) {
System.out.println("---最後讀出的長度是: "+ temp +" 位元組");
}
count++;
}
System.out.println("---最後讀出的長度是: "+ temp +" 位元組");
System.out.println("---長度是: "+ count +" 位元組");
} catch (IOException e) {
//TODO 自動生成的 catch 塊
e.printStackTrace();
} finally {
try{
if (streamReader != null) { streamReader.close(); }
}catch (IOException e) {
//TODO 自動生成的 catch 塊
e.printStackTrace();
}
}
}
}
輸出:
---長度是: 51281 位元組
---最後讀出的長度是: 81 位元組
---最後讀出的長度是: -1 位元組
---長度是: 51 位元組
4.2.2 輸出流OutputStream
package com.shuidi.iotest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest {
public static void main(String[] args) {
// TODO自動生成的方法存根
byte[] buffer = new byte[1024]; //一次取出的位元組數大小,緩衝區大小
int numberRead = 0;
FileInputStream input = null;
FileOutputStream out = null;
try {
input = new FileInputStream("FileInoutStreamTest.jpg");
out = new FileOutputStream("FileOutputStreamTest.jpg"); //如果檔案不存在會自動建立
while ((numberRead = input.read(buffer))!=-1) { //numberRead的目的在於防止最後一次讀取的位元組小於buffer長度
out.write(buffer, 0, numberRead); //否則會自動被填充0
}
} catch (IOException e) {
// TODO自動生成的 catch 塊
e.printStackTrace();
} finally {
try {
input.close();
out.close();
} catch (IOException e) {
// TODO自動生成的 catch 塊
e.printStackTrace();
}
}
}
}
無輸出
4.2.3 輸入輸出流DataInputStream/DataOutputStream
Demo:
package com.shuidi.iotest;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamTest {
public static void main(String[]args){
Member[] members = {new Member("Justin",90),
new Member("momor",95),
new Member("Bush",88)};
try {
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("DataStreamTest.txt"));
for(Member member:members){
//寫入UTF字串
dataOutputStream.writeUTF(member.getName());
//寫入int資料
dataOutputStream.writeInt(member.getAge());
}
//所有資料至目的地
dataOutputStream.flush();
//關閉流
dataOutputStream.close();
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("DataStreamTest.txt"));
//讀出資料並還原為物件
for(int i = 0;i < members.length;i++){
//讀出UTF字串
String name = dataInputStream.readUTF();
//讀出int資料
int score = dataInputStream.readInt();
members[i] = new Member(name,score);
}
//關閉流
dataInputStream.close();
//顯示還原後的資料
for(Member member : members){
System.out.printf("%s\t%d%n",member.getName(),member.getAge());
}
} catch (IOException e){
e.printStackTrace();
}
}
}
輸出:
Justin 90
momor 95
Bush 88
4.2.4 PushbackInputStream
package com.shuidi.iotest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
public class PushBackInputStreamTest {
public static void main(String[] args) throws IOException {
String str = "hello,rollenholt";
PushbackInputStream push = null; // 宣告回退流物件
ByteArrayInputStream bat = null; // 宣告位元組陣列流物件
bat = new ByteArrayInputStream(str.getBytes());
push = new PushbackInputStream(bat); // 建立回退流物件,將拆解的位元組陣列流傳入
int temp = 0;
while ((temp = push.read()) != -1) { // push.read()逐位元組讀取存放在temp中,如果讀取完成返回-1
if (temp == ',') { // 判斷讀取的是否是逗號
push.unread('u'); //回到temp的位置
temp = push.read(); //接著讀取位元組
System.out.print("(回退" + (char) temp + ") "); // 輸出回退的字元
} else {
System.out.print((char) temp); // 否則輸出字元
}
}
}
}
輸出:
hello(回退u) rollenholt
4.2.5 SequenceInputStream
有些情況下,當我們需要從多個輸入流中向程式讀入資料。此時,可以使用合併流,將多個輸入流合併成一個SequenceInputStream流物件。SequenceInputStream會將與之相連線的流集組合成一個輸入流並從第一個輸入流開始讀取,直到到達檔案末尾,接著從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的檔案末尾為止。 合併流的作用是將多個源合併合一個源。其可接收列舉類所封閉的多個位元組流物件。
package com.shuidi.iotest;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;
public class SequenceInputStreamTest {
/**
* @param args
* SequenceInputStream合併流,將與之相連線的流集組合成一個輸入流並從第一個輸入流開始讀取,
* 直到到達檔案末尾,接著從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的檔案末尾為止。
* 合併流的作用是將多個源合併合一個源。可接收列舉類所封閉的多個位元組流物件。
*/
public static void main(String[] args) {
doSequence();
}
private static void doSequence() {
// 建立一個合併流的物件
SequenceInputStream sis = null;
// 建立輸出流。
BufferedOutputStream bos = null;
try {
// 構建流集合。
Vector<InputStream> vector = new Vector<InputStream>();
vector.addElement(new FileInputStream("SequenceInputStreamTest1.txt"));
vector.addElement(new FileInputStream("SequenceInputStreamTest2.txt"));
vector.addElement(new FileInputStream("SequenceInputStreamTest3.txt"));
Enumeration<InputStream> e = vector.elements();
sis = new SequenceInputStream(e);
bos = new BufferedOutputStream(new FileOutputStream("SequenceInputStreamTest4.txt"));
// 讀寫資料
byte[] buf = new byte[1024];
int len = 0;
while ((len = sis.read(buf)) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
if (sis != null)
sis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
輸入:
SequenceInputStreamTest1.txt:1
SequenceInputStreamTest2.txt:2
SequenceInputStreamTest3.txt:3
輸出:
SequenceInputStreamTest4.txt:123
4.2.6 PrintStream
System.out.print():System.out這個物件就是PrintStream,這個我們不做過多示例
4.3 字元流
4.3.1 FileReader/PrintWriter
package com.shuidi.iotest;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
public class FileReaderTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO自動生成的方法存根
char[] buffer = new char[512]; //一次取出的位元組數大小,緩衝區大小
int numberRead = 0;
FileReader reader = null; //讀取字元檔案的流
PrintWriter writer = null; //寫字元到控制檯的流
try {
reader = new FileReader("FileReaderTest.txt");
writer = new PrintWriter(System.out); //PrintWriter可以輸出字元到檔案,也可以輸出到控制檯
while ((numberRead = reader.read(buffer))!=-1) {
writer.write(buffer, 0, numberRead);
}
} catch (IOException e) {
// TODO自動生成的 catch 塊
e.printStackTrace();
}finally{
try {
reader.close();
} catch (IOException e) {
// TODO自動生成的 catch 塊
e.printStackTrace();
}
writer.close(); //這個不用拋異常
}
}
}
輸出:
FileReaderTest.txt:shuidi
shuidi
4.3.2 BufferedReader/BufferedWriter
package com.shuidi.iotest;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedReaderWriterTest {
public static void main(String[] args) {
// TODO自動生成的方法存根
try {
concennateFile("BufferedReader.txt");
} catch (IOException e) {
// TODO自動生成的 catch 塊
e.printStackTrace();
}
}
@SuppressWarnings("resource")
public static void concennateFile(String fileName) throws IOException{
String str;
//構建對該檔案您的輸入流
BufferedWriter writer = new BufferedWriter(new FileWriter("BufferedWriter.txt"));
BufferedReader reader = new BufferedReader(new FileReader(fileName));
try {
while ((str = reader.readLine()) != null) {
writer.write(str);
writer.newLine();
}
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
}
BufferedReader.txt:
1
2
3
4
5
BufferedWriter.txt:
1
2
3
4
5
4.3.1 StreamTokenizer
這個類非常有用,它可以把輸入流解析為標記(token), StreamTokenizer 並非派生自InputStream或者OutputStream,而是歸類於io庫中.
package com.shuidi.iotest;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;
public class StreamTokenizerTest {
/**
* 統計字元數
* @param fileName 檔名
* @return 字元數
*/
public static void main(String[] args) {
String fileName = "StreamTokenizerTest.txt";
statis(fileName);
}
public static long statis(String fileName) {
FileReader fileReader = null;
try {
fileReader = new FileReader(fileName);
//建立分析給定字元流的標記生成器
StreamTokenizer st = new StreamTokenizer(new BufferedReader(
fileReader));
//ordinaryChar方法指定字元引數在此標記生成器中是“普通”字元。
//下面指定單引號、雙引號和註釋符號是普通字元
st.ordinaryChar('\'');
st.ordinaryChar('\"');
st.ordinaryChar('/');
String s;
int numberSum = 0;
int wordSum = 0;
int symbolSum = 0;
int total = 0;
//nextToken方法讀取下一個Token.
//TT_EOF指示已讀到流末尾的常量。
while (st.nextToken() != StreamTokenizer.TT_EOF) {
//在呼叫 nextToken 方法之後,ttype欄位將包含剛讀取的標記的型別
switch (st.ttype) {
//TT_EOL指示已讀到行末尾的常量。
case StreamTokenizer.TT_EOL:
break;
//TT_NUMBER指示已讀到一個數字標記的常量
case StreamTokenizer.TT_NUMBER:
//如果當前標記是一個數字,nval欄位將包含該數字的值
s = String.valueOf((st.nval));
System.out.println("數字有:"+s);
numberSum ++;
break;
//TT_WORD指示已讀到一個文字標記的常量
case StreamTokenizer.TT_WORD:
//如果當前標記是一個文字標記,sval欄位包含一個給出該文字標記的字元的字串
s = st.sval;
System.out.println("單詞有: "+s);
wordSum ++;
break;
default:
//如果以上3中型別都不是,則為英文的標點符號
s = String.valueOf((char) st.ttype);
System.out.println("標點有: "+s);
symbolSum ++;
}
}
System.out.println("數字有 " + numberSum+"個");
System.out.println("單詞有 " + wordSum+"個");
System.out.println("標點符號有: " + symbolSum+"個");
total = symbolSum + numberSum +wordSum;
System.out.println("Total = " + total);
return total;
} catch (Exception e) {
e.printStackTrace();
return -1;
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e1) {
}
}
}
}
}
輸入:
StreamTokenizerTest.txt
'haha'
word
"I love coding" ,。
23223 3523
輸出:
標點有: '
單詞有: haha
標點有: '
單詞有: word
標點有: "
單詞有: I
單詞有: love
單詞有: coding
標點有: "
單詞有: ,。
數字有:23223.0
數字有:3523.0
數字有 2個
單詞有 6個
標點符號有: 4個
Total = 12
5.參考文獻
相關推薦
【Java基礎之五】Java中IO詳解
1.Java IO簡介 可能學過計算機組裝與維修的同學都知道I/O裝置,翻譯過來也就是Input/Output(輸入輸出裝置),在硬體中鍵盤、滑鼠 屬於 輸入裝置,顯示器、印表機等屬於輸出裝置,這裡輸入輸出參考物是計算機本身。 java.io包從巨集觀上來
【JAVA基礎知識學習】Java中的String,StringBuilder,StringBuffer三者的區別
最近在學習Java的時候,遇到了這樣一個問題,就是String,StringBuilder以及StringBuffer這三個類之間有什麼區別呢,自己從網上搜索了一些資料,有所瞭解了之後在這裡整理一下,便於大家觀看,也便於加深自己學習過程中對這些知識點的記憶,如果哪
【JAVA基礎小問題】java中實現多型的機制是什麼?
靠的是父類或介面定義的引用變數可以指向子類或具體實現類的例項物件,而程式呼叫的方法在執行期才動態繫結,就是引用變數所指向的具體例項物件的方法,也就是記憶體里正在執行的那個物件的方法,而不是引用變數的型別中定義的方法。
【java基礎之異常】死了都要try,不淋漓盡致地catch我不痛快!
@[toc] # 1、異常 ## 1.1 異常概念 **異常** :簡單說就是不正常執行,最終導致JVM的非正常停止。 在Java等面向物件的程式語言中,異常本身是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常的方式是中斷處理。 > 異常指的並不是語法錯誤,語法錯了,編譯
【MongoDb學習之路】Java利用MongoClient類連線MongoDB資料庫
專案需要 mongo-java-driver-3.0.2 .jar 【重點看加粗字型,方法體中註釋的都是系統連線引數】 package cn.com.mongodb; import com.mongodb.DB; import com.mongodb.DBColl
Java基礎(五)Java中的引數傳遞機制
通過前一篇文章的介紹,我們從整體上明白了,Java類中變數的差異性、不同變數在記憶體中的儲存位置,以及變數的生命週期等。今天,我們來看一下Java中引數傳遞的機制。 形參:方法宣告時包含的引數宣告 實參:呼叫方法時,實際傳給形參的引數值 Java方法的引數傳遞機制:
【javaMail】【1.基礎發郵件】java mail 傳送plain text 郵件 helloworld
簡介 JavaMail,顧名思義,提供給開發者處理電子郵件相關的程式設計介面。它是Sun釋出的用來處理email的API。它可以方便地執行一些常用的郵件傳輸。 雖然JavaMail是Sun的API之一,但它目前還沒有被加在標準的java開發工具包中(Java Develop
【django基礎之ORM】
配置文件 nbsp rom 查看 如果 並不是 rem decimal 屬性和方法 一、定義 1.什麽是ORM? ORM,即Object-Relational Mapping(對象關系映射),它的作用是在關系型數據庫和業務實體對象之間作一個映射,這樣,我們在具體的操作業務對
Java基礎之第一個Java程式HelloWorld及註釋
程式碼如下: // 一個檔案中只能有一個共有的類,並且與檔名稱一致,大小寫注意 public class HelloWorld{ // 程式的入口 public static void main
【redis學習之五】基於redis的分散式鎖實現
在單個JVM中,我們可以很方便的用sychronized或者reentrantLock在資源競爭時進行加鎖,保證高併發下資料執行緒安全。但是若是分散式環境下,多個JVM同時對一個資源進行競爭時,我們該如何保證執行緒安全呢?分散式鎖便能實現我們的要求。 &n
Java基礎(五):Java實現圖片無損任意角度旋轉
【前言】 在做專案的時候遇到一個業務需要對圖片進行旋轉,於是找到一個工具類,親測有效;在此與大家共享,需要用時可以直接用哈! 【實戰】 一、旋轉工具類程式碼: package zh.test.utils; import java.awt.*;
【C++基礎之八】函式指標和回撥函式
C++很多類庫都喜歡用回撥函式,MFC中的定時器,訊息機制,hook機制等待,包括現在在研究的cocos2d-x中也有很多的回撥函式。1.回撥函式什麼是回撥函式呢?回撥函式其實就是一個通過函式指標呼叫的函式!假如你把A函式的指標當作引數傳給B函式,然後在B函式中通過A函式傳進
【C++基礎之四】c++ char in short long double佔位元組數
所以,int,long int,short int的寬度都可能隨編譯器而異。但有幾條鐵定的原則(ANSI/ISO制訂的): 1 sizeof(short int)<=sizeof(int) 2 sizeof(int)<=sizeof(lo
java基礎之序列化 Java物件表示方式1:序列化、反序列化和transient關鍵字的作用
轉載自https://www.cnblogs.com/szlbm/p/5504166.html Java物件表示方式1:序列化、反序列化和transient關鍵字的作用 平時我們在Java記憶體中的物件,是無 法進行IO操作或者網路通訊的
【Java多執行緒】Executor框架的詳解
在Java中,使用執行緒來非同步執行任務。Java執行緒的建立與銷燬需要一定的開銷,如果我們為每一個任務建立一個新執行緒來執行,這些執行緒的建立與銷燬將消耗大量的計算資源。同時,為每一個任務建立一個新執行緒來執行,這種策略可能會使處於高負荷狀態的應用最終崩潰。 Java執行
【CSS筆記之五】IE6/IE7/IE8下float:right的異常及其解決方法
示例分析程式碼: <div id="channel_tit" class="round_top"> <span class="rtl rtl1"></span> <h2>安卓首頁><a href=
java基礎 String,equal,final等詳解
對於這個系列裡的問題,每個學Java的人都應該搞懂。當然,如果只是學Java玩玩就無所謂了。如果你認為自己已經超越初學者了,卻不很懂這些問題,請將你自己重歸初學者行列。內容均來自於CSDN的經典老貼。 問題一:我聲明瞭什麼! String s = "Hello world!"; 許多人都
關於java基礎--日期類與日曆類Calendar詳解測試
1,Date Date d = new Date(); //建立日期比當前延遲100毫秒後的日期 Date d1 = new Date(System.currentTimeMillis()+100); 1-1,After()判斷d表示的日期是否在b1表示的之後 Syste
java程式碼之美(13)--- Predicate詳解
java程式碼之美(13)--- Predicate詳解 遇到Predicate是自己在自定義Mybatis攔截器的時候,在攔截器中我們是通過反射機制獲取物件的所有屬性,再檢視這些屬性上是否有我們自定義的UUID註解。 如果有該註解,那麼就給該屬性賦值UUID隨機字串,作為主鍵儲存到資料庫。所以前提條件就是
C#網絡編程基礎之進程和線程詳解
詳解 面試 ring develop -a display asp.net codes frame 在C#的網絡編程中,進程和線程是必備的基礎知識,同時也是一個重點,所以我們要好好的掌握一下。 一:概念 首先我們要知道什麽是”進程”,什麽是“線程”,好,查一下baik