本文目錄一覽:
- 1、關於java中的io操作 新手有些不懂
- 2、java io流的典型使用方式有幾種
- 3、什麼是java IO涉及的領域有哪些?
- 4、Java中IO與NIO的區別和使用場景
- 5、java中io的用法
- 6、Java中的I/O流的基本知識
關於java中的io操作 新手有些不懂
String str=”helloworld”;
//將str轉換成位元組數組輸入流中
ByteArrayInputStream bis=new ByteArrayInputStream(str.getBytes());
//輸出流
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int temp=0;//因為每次read讀的都是數量,所以是int類型
while((temp=bis.read())!=-1){
//bis.read();是讀輸入流裡面的位元組,返回的是讀的數量,給了temp。讀完這個下次循環自動讀下一個位元組。讀到未,讀不到了,就返回-1.所有while在-1是停止循環
char c=(char)temp;//將讀到的位元組轉換成字元,一個英文一個位元組
bos.write(Character.toLowerCase(c));
//讀到的位元組轉成小寫的位元組寫到輸出流裡面(toUpperCase才是大寫)
}
String newStr=bos.toString();//將輸出流數組裡面的位元組給newStr
bis.close();//關閉流
bos.close();//關閉流
System.out.println(newStr);//列印
java io流的典型使用方式有幾種
Java中IO流分成兩大類,
一種是輸入流,所有的輸入流都直接或間接繼承自InputStream抽象類,輸入流作為數據的來源,我們可以通過輸入流的read方法讀取位元組數據;
另一種是輸出流,所有的輸出流都直接或間接繼承自OutputStream抽象類,輸出流接收數據,可以通過write方法寫入位元組數據。
Java的IO流類中,大部分的輸入流和輸出流都是成對存在的,即如果存在XXXInputStream,那麼就存在XXXOutputStream,反之亦然。SequenceInputStream和StringBufferInputStream是特例,沒有對應的SequenceOutputStream類和StringBufferOutputStream類,許多IO操作都可能會拋出IOException異常,比如read、write、close操作。
以下是Java的IO流中常見的輸入流,由於每個輸入流都有其對應的輸出流,所以此處就不再列出輸出流的繼承結構圖。
1、ByteArrayInputStream ByteArrayOutputStream:
ByteArrayInputStream構造函數中需要傳入一個byte數組作為數據源,當執行read操作時,就會從該數組中讀取數據,正如其名,是一種基於位元組數組實現的一種簡單輸入流,顯而易見的是,如果在構造函數中傳入了null作為位元組數據,那麼在執行read操作時就會出現NullPointerException異常,但是在構造函數初始化階段不會拋出異常;與之相對應的是ByteArrayOutputStream,其內部也有一個位元組數組用於存儲write操作時寫入的數據,在構造函數中可以傳入一個size指定其內部的byte數組的大小,如果不指定,那麼默認它會將byte數組初始化為32位元組,當持續通過write向ByteArrayOutputStream中寫入數據時,如果其內部的byte數組的剩餘空間不能夠存儲需要寫入的數據,那麼那麼它會通過調用內部的ensureCapacity
方法對其內部維護的byte數組進行擴容以存儲所有要寫入的數據,所以不必擔心其內部的byte數組太小導致的IndexOutOfBoundsException之類的異常。
2、FileInputStream FileOutputStream
FileInputStream 能夠將文件作為數據源,讀取文件中的流,通過File對象或文件路徑等初始化,在其構造函數中,如果傳入的File對象(或與其相對應的文件路徑所表示的File對象)不存在或是一個目錄而不是文件或者由於其他原因無法打開讀取數據,都會導致在初始化階段導致拋出FileNotFoundException異常;與FileInputStream 相對應的是FileOutputStream,可以通過FileOutputStream向文件中寫入數據,也需要通過File對象或文件路徑對其初始化,如同FileInputStream ,如果傳入的File對象(或與其相對應的文件路徑所表示的File對象)是一個目錄而不是文件或者由於其他原因無法創建該文件寫入數據,都會導致在初始化階段拋出FileNotFoundException異常。
3、PipedInputStream PipedOutputStream
PipedInputStream和PipedOutputStream一般是結合使用的,這兩個類用於在兩個線程間進行管道通信,一般在一個線程中執行PipedOutputStream 的write操作,而在另一個線程中執行PipedInputStream的read操作。可以在構造函數中傳入相關的流將PipedInputStream 和PipedOutputStream 綁定起來,也可以通過二者的connect方法將二者綁定起來,一旦二者進進行了綁定,那麼PipedInputStream的read方法就會自動讀取PipedOutputStream寫入的數據。PipedInputStream的read操作是阻塞式的,當執行PipedOutputStream的write操作時,PipedInputStream會在另一個線程中自動讀取PipedOutputStream寫入的內容,如果PipedOutputStream一直沒有執行write操作寫入數據,那麼PipedInputStream的read方法會一直阻塞PipedInputStream的read方法所運行的線程直至讀到數據。單獨使用PipedInputStream或單獨使用PipedOutputStream時沒有任何意義的,必須將二者通過connect方法(或在構造函數中傳入對應的流)進行連接綁定,如果單獨使用其中的某一個類,就會觸發IOException: Pipe Not Connected.
4、ObjectInputStream ObjectOutputStream
ObjectOutputStream具有一系列writeXXX方法,在其構造函數中可以摻入一個OutputStream,可以方便的向指定的輸出流中寫入基本類型數據以及String,比如writeBoolean、writeChar、writeInt、writeLong、writeFloat、writeDouble、writeCharts、writeUTF等,除此之外,ObjectOutputStream還具有writeObject方法。writeObject方法中傳入的類型必須實現了Serializable介面,從而在執行writeObject操作時將對象進行序列化成流,並將其寫入指定的輸出流中。與ObjectOutputStream相對應的是ObjectInputStream,ObjectInputStream有與OutputStream中的writeXXX系列方法完全對應的readXXX系列方法,專門用於讀取OutputStream通過writeXXX寫入的數據。
5、SequenceInputStream
SequenceInputStream 主要是將兩個(或多個)InputStream在邏輯上合併為一個InputStream,比如在構造函數中傳入兩個InputStream,分別為in1和in2,那麼SequenceInputStream在讀取操作時會先讀取in1,如果in1讀取完畢,就會接著讀取in2。在我們理解了SequenceInputStream 的作用是將兩個輸入流合併為一個輸入流之後,我們就能理解為什麼不存在對應的SequenceOutputStream 類了,因為將一個輸出流拆分為多個輸出流是沒有意義的。
6、StringBufferInputStream
StringBufferInputStream允許通過在構造函數中傳入字元串以讀取位元組,在讀取時內部主要調用了String的charAt方法。與SequenceInputStream類似,StringBufferInputStream也沒有對應的OutputStream,即不存在StringBufferOutputStream類。Java沒有設計StringBufferOutputStream類的理由也很簡單,我們假設StringBufferOutputStream存在,那麼StringBufferOutputStream應該是內部通過執行write操作寫入數據更新其內部的String對象,比如有可能是通過StringBuilder來實現,但是這樣做毫無意義,因為一旦我們String的構造函數中可以直接傳入位元組數組構建字元串,簡單明了,所以設計StringBufferOutputStream就沒有太大的必要了。StringBufferInputStream這個類本身存在一點問題,它不能很好地將字元數組轉換為位元組數組,所以該類被Java標記為廢棄的(Deprecated),其官方推薦使用StringReader作為代替。
7、FilterInputStream FilterOutputStream
FilterInputStream包含了其他的輸入流,說具體點就是在其構造函數中需要傳入一個InputStream並將其保存在其名為in的欄位中,FilterInputStream只是簡單的覆蓋了所有的方法,之所說是簡單覆蓋是因為在每個覆蓋函數中,它只是調用內部的保存在in欄位中的InputStream所對應的方法,比如在其覆蓋read方法時,內部只是簡單調用了in.read()方法。FilterInputStream的子類可以進一步覆蓋某些方法以保持介面不變的情況下實現某一特性(比如其子類有的可以通過使用緩存優化讀取的效率)或者提供一些其他額外的實用方法。所以在使用時FilterInputStream可以讓傳入的InputStream具有一些額外的特性,即對構造函數傳入的InputStream進行了一層包裹,使用了典型的裝飾著模式,如果只看FilterInputStream本身這一個類的話,則該類自己本身意義不大,因為其只是通過內部的欄位in簡單覆寫某些方法。但是如果將FilterInputStream 和其子類結合起來使用話,那麼就很有用了。比如FilterInputStream 有兩個子類BufferedInputStream和DataInputStream,這兩個類在下面還會詳細介紹。BufferedInputStream對read操作做了優化,每次讀操作時都讀取一大塊數據,然後將其放入內部維護的一個位元組數組緩衝區中。當外面調用BufferedInputStream的read方法時,首先去該緩衝區中讀取數據,這樣就避免了頻繁的實際的讀操作,BufferedInputStream對外沒有暴露額外的其他方法,但是其內部的read方法已經經過優化了,所以在執行讀操作的時候效率更高。DataInputStream與ObjectInputStream有點類似,可以通過一些readXXX方法讀取基本類型的數據,這是非常有用的一些方法。
8、BufferedInputStream BufferedOutputStream
如上面所介紹的那樣,在BufferedInputStream的構造函數中需要傳入一個InputStream, BufferedInputStream內部有一個位元組數組緩衝區,每次執行read操作的時候就從這buf中讀取數據,從buf中讀取數據沒有多大的開銷。如果buf中已經沒有了要讀取的數據,那麼就去執行其內部綁定的InputStream的read方法,而且是一次性讀取很大一塊數據,以便填充滿buf緩衝區。緩衝區buf的默認大小是8192位元組,也就是8K,在構造函數中我們也可以自己傳入一個size指定緩衝區的大小。由於我們在執行BufferedInputStream的read操作的時候,很多時候都是從緩衝區中讀取的數據,這樣就大大減少了實際執行其指定的InputStream的read操作的次數,也就提高了讀取的效率。與BufferedInputStream 相對的是BufferedOutputStream。在BufferedOutputStream的構造函數中我們需要傳入一個OutputStream,這樣就將BufferedOutputStream與該OutputStream綁定在了一起。BufferedOutputStream內部有一個位元組緩衝區buf,在執行write操作時,將要寫入的數據先一起緩存在一起,將其存入位元組緩衝區buf中,buf是有限定大小的,默認的大小是8192位元組,即8KB,當然也可以在構造函數中傳入size指定buf的大小。該buf只要被指定了大小之後就不會自動擴容,所以其是有限定大小的,既然有限定大小,就會有被填充完的時刻,當buf被填充完畢的時候會調用BufferedOutputStream的flushBuffer方法,該方法會通過調用其綁定的OutputStream的write方法將buf中的數據進行實際的寫入操作並將buf的指向歸零(可以看做是將buf中的數據清空)。如果想讓緩存區buf中的數據理解真的被寫入OutputStream中,可以調用flush方法,flush方法內部會調用flushBuffer方法。由於buf的存在,會大大減少實際執行OutputStream的write操作的次數,優化了寫的效率。
什麼是java IO涉及的領域有哪些?
IO部分的內容是很龐大的,因為它涉及的領域很廣泛:標準輸入輸出,文件的操作,網路上的數據流,字元串流,對象流,zip文件流。
Java中IO與NIO的區別和使用場景
在java2以前,傳統的socket IO中,需要為每個連接創建一個線程,當並發的連接數量非常巨大時,線程所佔用的棧內存和CPU線程切換的開銷將非常巨大。java5以後使用NIO,不再需要為每個線程創建單獨的線程,可以用一個含有限數量線程的線程池,甚至一個線程來為任意數量的連接服務。由於線程數量小於連接數量,所以每個線程進行IO操作時就不能阻塞,如果阻塞的話,有些連接就得不到處理,NIO提供了這種非阻塞的能力。
NIO 設計背後的基石:反應器模式,用於事件多路分離和分派的體系結構模式。
反應器(Reactor):用於事件多路分離和分派的體系結構模式
通常的,對一個文件描述符指定的文件或設備, 有兩種工作方式: 阻塞 與非阻塞 。所謂阻塞方式的意思是指, 當試圖對該文件描述符進行讀寫時, 如果當時沒有東西可讀,或者暫時不可寫, 程序就進入等待 狀態, 直到有東西可讀或者可寫為止。而對於非阻塞狀態, 如果沒有東西可讀, 或者不可寫, 讀寫函數馬上返回, 而不會等待 。
一種常用做法是:每建立一個Socket連接時,同時創建一個新線程對該Socket進行單獨通信(採用阻塞的方式通信)。這種方式具有很高的響應速度,並且控制起來也很簡單,在連接數較少的時候非常有效,但是如果對每一個連接都產生一個線程的無疑是對系統資源的一種浪費,如果連接數較多將會出現資源不足的情況。
另一種較高效的做法是:伺服器端保存一個Socket連接列表,然後對這個列表進行輪詢,如果發現某個Socket埠上有數據可讀時(讀就緒),則調用該socket連接的相應讀操作;如果發現某個 Socket埠上有數據可寫時(寫就緒),則調用該socket連接的相應寫操作;如果某個埠的Socket連接已經中斷,則調用相應的析構方法關閉該埠。這樣能充分利用伺服器資源,效率得到了很大提高。
傳統的阻塞式IO,每個連接必須要開一個線程來處理,並且沒處理完線程不能退出。
非阻塞式IO,由於基於反應器模式,用於事件多路分離和分派的體系結構模式,所以可以利用線程池來處理。事件來了就處理,處理完了就把線程歸還。而傳統阻塞方式不能使用線程池來處理,假設當前有10000個連接,非阻塞方式可能用1000個線程的線程池就搞定了,而傳統阻塞方式就需要開10000個來處理。如果連接數較多將會出現資源不足的情況。非阻塞的核心優勢就在這裡。
為什麼會這樣,下面就對他們做進一步細緻具體的分析:
首先,我們來分析傳統阻塞式IO的瓶頸在哪裡。在連接數不多的情況下,傳統IO編寫容易方便使用。但是隨著連接數的增多,問題傳統IO就不行了。因為前面說過,傳統IO處理每個連接都要消耗一個線程,而程序的效率當線程數不多時是隨著線程數的增加而增加,但是到一定的數量之後,是隨著線程數的增加而減少。這裡我們得出結論,傳統阻塞式IO的瓶頸在於不能處理過多的連接。
然後,非阻塞式IO的出現的目的就是為了解決這個瓶頸。而非阻塞式IO是怎麼實現的呢?非阻塞IO處理連接的線程數和連接數沒有聯繫,也就是說處理 10000個連接非阻塞IO不需要10000個線程,你可以用1000個也可以用2000個線程來處理。因為非阻塞IO處理連接是非同步的。當某個鏈接發送請求到伺服器,伺服器把這個連接請求當作一個請求”事件”,並把這個”事件”分配給相應的函數處理。我們可以把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就可以非同步的處理多個事件。而阻塞式IO的線程的大部分時間都浪費在等待請求上了。
所謂阻塞式IO流,就是指在從數據流當中讀寫數據的的時候,阻塞當前線程,直到IO流可以
重新使用為止,你也可以使用流的avaliableBytes()函數看看當前流當中有多少位元組可以讀取,這樣
就不會再阻塞了。
java中io的用法
java中關於io流,最終操作還是最底層的InputStream和OutputStream
其它的對象如FileoutPutStream,或者DateoutputStream只是對OutputStream進行封裝,有的是為了方便操作有的是為了加快速度
例如DateoutputStream是為了操作的方便,它實現ObjectOutput介面,可以將某些java的數據類型直接寫到文件或者請求中,然後又可以直接取出來,而不用讀了過後解析
例如讀了兩位元組,轉成String再判斷如果是數字則強轉成int,這裡面就可以直接readInt()相當於一層封裝,還是用了inputString和outputStream,如果你研究一下序列化與反序列化(ObjectOutputStream,ObjectInputStream)你的感受會更深,因為它可以直接將一個對象寫入文件或者請求中,然後讀的時候直接就可以讀出來,這樣用起來非常方便
所以dos=new DataoutputStream(new FileOutputStream(tempfile));
FileOutputStream是將流寫入文件,而DataoutputStream則是為了方便將java基本數據類型直接寫到文件裡面,與直接用FileoutPutStream區別就在於讀該文件的時候前者可以直接讀出int等數據類型,而後者你需要讀了位元組流然後自己解析,得到你想要的值
還有的就是為了加快速度如BufferedInputStream和BufferedOutputStream兩者就是運用緩存,存了多個位元組後一次性寫入或者讀出,這樣加快了讀寫速度。
至於文件編碼,則是在寫的時候如果你沒設編碼則按系統默認編碼來寫,位元組存儲格式和長度不一樣,這些應該在讀文件或者寫的時候就設置好,不論是以位元組寫還是以字元寫,流已經被編碼過了
Java中的I/O流的基本知識
Java文件操作大全
1.創建文件夾
//import java.io.*;
File myFolderPath = new File(%%1);
try {
if (!myFolderPath.exists()) {
myFolderPath.mkdir();
}
}
catch (Exception e) {
System.out.println(“新建目錄操作出錯”);
e.printStackTrace();
}
2.創建文件
//import java.io.*;
File myFilePath = new File(%%1);
try {
if (!myFilePath.exists()) {
myFilePath.createNewFile();
}
FileWriter resultFile = new FileWriter(myFilePath);
PrintWriter myFile = new PrintWriter(resultFile);
myFile.println(%%2);
resultFile.close();
}
catch (Exception e) {
System.out.println(“新建文件操作出錯”);
e.printStackTrace();
}
3.刪除文件
//import java.io.*;
File myDelFile = new File(%%1);
try {
myDelFile.delete();
}
catch (Exception e) {
System.out.println(“刪除文件操作出錯”);
e.printStackTrace();
}
4.刪除文件夾
//import java.io.*;
File delFolderPath = new File(%%1);
try {
delFolderPath.delete(); //刪除空文件夾
}
catch (Exception e) {
System.out.println(“刪除文件夾操作出錯”);
e.printStackTrace();
}
5.刪除一個文件下夾所有的文件夾
//import java.io.*;
File delfile=new File(%%1);
File[] files=delfile.listFiles();
for(int i=0;ifiles.length;i++){
if(files[i].isDirectory()){
files[i].delete();
}
}
6.清空文件夾
//import java.io.*;
File delfilefolder=new File(%%1);
try {
if (!delfilefolder.exists()) {
delfilefolder.delete();
}
delfilefolder.mkdir();
}
catch (Exception e) {
System.out.println(“清空目錄操作出錯”);
e.printStackTrace();
}
7.讀取文件
//import java.io.*;
// 逐行讀取數據
FileReader fr = new FileReader(%%1);
BufferedReader br = new BufferedReader(fr);
String %%2 = br.readLine();
while (%%2 != null) {
%%3
%%2 = br.readLine();
}
br.close();
fr.close();
8.寫入文件
//import java.io.*;
// 將數據寫入文件
try {
FileWriter fw = new FileWriter(%%1);
fw.write(%%2);
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
9.寫入隨機文件
//import java.io.*;
try {
RandomAcessFile logFile=new RandomAcessFile(%%1,”rw”);
long lg=logFile.length();
logFile.seek(%%2);
logFile.writeByte(%%3);
}catch(IOException ioe){
System.out.println(“無法寫入文件:”+ioe.getMessage());
}
10.讀取文件屬性
//import java.io.*;
// 文件屬性的取得
File af = new File(%%1);
if (af.exists()) {
System.out.println(f.getName() + “的屬性如下: 文件長度為:” + f.length());
System.out.println(f.isFile() ? “是文件” : “不是文件”);
System.out.println(f.isDirectory() ? “是目錄” : “不是目錄”);
System.out.println(f.canRead() ? “可讀取” : “不”);
System.out.println(f.canWrite() ? “是隱藏文件” : “”);
System.out.println(“文件夾的最後修改日期為:” + new Date(f.lastModified()));
} else {
System.out.println(f.getName() + “的屬性如下:”);
System.out.println(f.isFile() ? “是文件” : “不是文件”);
System.out.println(f.isDirectory() ? “是目錄” : “不是目錄”);
System.out.println(f.canRead() ? “可讀取” : “不”);
System.out.println(f.canWrite() ? “是隱藏文件” : “”);
System.out.println(“文件的最後修改日期為:” + new Date(f.lastModified()));
}
if(f.canRead()){
%%2
}
if(f.canWrite()){
%%3
}
11.寫入屬性
//import java.io.*;
File filereadonly=new File(%%1);
try {
boolean b=filereadonly.setReadOnly();
}
catch (Exception e) {
System.out.println(“拒絕寫訪問:”+e.printStackTrace());
}
12.枚舉一個文件夾中的所有文件
//import java.io.*;
//import java.util.*;
LinkedListString folderList = new LinkedListString();
folderList.add(%%1);
while (folderList.size() 0) {
File file = new File(folderList.peek());
folderList.removeLast();
File[] files = file.listFiles();
ArrayListFile fileList = new ArrayListFile();
for (int i = 0; i files.length; i++) {
if (files[i].isDirectory()) {
folderList.add(files[i].getPath());
} else {
fileList.add(files[i]);
}
}
for (File f : fileList) {
%%2=f.getAbsoluteFile();
%%3
}
}
13.複製文件夾
//import java.io.*;
//import java.util.*;
LinkedListString folderList = new LinkedListString();
folderList.add(%%1);
LinkedListString folderList2 = new LinkedListString();
folderList2.add(%%2+ %%1.substring(%%1.lastIndexOf(“\\”)));
while (folderList.size() 0) {
(new File(folderList2.peek())).mkdirs(); // 如果文件夾不存在 則建立新文件夾
File folders = new File(folderList.peek());
String[] file = folders.list();
File temp = null;
try {
for (int i = 0; i file.length; i++) {
if (folderList.peek().endsWith(File.separator)) {
temp = new File(folderList.peek() + File.separator
+ file[i]);
} else {
temp = new File(folderList.peek() + File.separator
+ file[i]);
}
if (temp.isFile()) {
FileInputStream input = new FileInputStream(temp);
FileOutputStream output = new FileOutputStream(
folderList2.peek() + File.separator
+ (temp.getName()).toString());
byte[] b = new byte[5120];
int len;
while ((len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.flush();
output.close();
input.close();
}
if (temp.isDirectory()) {// 如果是子文件夾
for (File f : temp.listFiles()) {
if (f.isDirectory()) {
folderList.add(f.getPath());
folderList2.add(folderList2.peek()
+ File.separator + f.getName());
}
}
}
}
} catch (Exception e) {
//System.out.println(“複製整個文件夾內容操作出錯”);
e.printStackTrace();
}
folderList.removeFirst();
folderList2.removeFirst();
}
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/255073.html