I/O流講解

本文來自:曹勝歡博客專欄:http://blog.csdn.net/csh624366188


????? 在軟件開發中,數據流和數據庫操作占據了一個很重要的位置,所以,熟悉操作數據流和數據庫,對于每一個開發者來說都是很重要的,今天就來總結一下I/O,數據庫操作

一:從數據流開始

首先先有一個結構圖看一下整個數據流中的API結構和對象繼承關系信息:


其他常用與流有關的對象:


首先從字符流開始

1、字符流的由來:

????因為文件編碼的不同,而有了對字符進行高效操作的字符流對象。

????原理:其實就是基于字節流讀取字節時,去查了指定的碼表。

字節流和字符流的區別:

1,字節流讀取的時候,讀到一個字節就返回一個字節。字符流使用了字節流讀到一個或多個字節(中文對應的字節數是兩個,UTF-8碼表中是3個字節)時。先去查指定的編碼表,將查到的字符返回。

2,字節流可以處理所有類型數據,如圖片,mp3,avi。而字符流只能處理字符數據。

結論:只要是處理純文本數據,就要優先考慮使用字符流。除此之外都用

節流。

基本的讀寫操作方式:

因為數據通常都以文件形式存在。

所以就要找到IO體系中可以用于操作文件的流對象。

通過名稱可以更容易獲取該對象。

因為IO體系中的子類名后綴絕大部分是父類名稱。而前綴都是體現子類功能的名字。

Reader

???|--InputStreamReader

????????????|--FileReader:專門用于處理文件的字符讀取流對象。

Writer

????|--OutputStreamWriter

??????????????????|--FileWriter:專門用于處理文件的字符寫入流對象。

Reader中的常見的方法:

1,int?read():讀取一個字符。返回的是讀到的那個字符。如果讀到流的末尾,返回-1.

2,int?read(char[]):將讀到的字符存入指定的數組中,返回的是讀到的字符個數,也就是往數組里裝的元素的個數。如果讀到流的末尾,返回-1.

3,close():讀取字符其實用的是window系統的功能,就希望使用完畢后,進行資源的釋放

Writer中的常見的方法:

1,write(ch):?將一個字符寫入到流中。

2,write(char[]):?將一個字符數組寫入到流中。

3,write(String):?將一個字符串寫入到流中。

4,flush():刷新流,將流中的數據刷新到目的地中,流還存在。

5,close():關閉資源:在關閉前會先調用flush(),刷新流中的數據去目的地。然流關閉。

FileWriter:該類沒有特有的方法只有自己的構造函數。該類特點在于

1,用于處理文本文件。

2,該類中有默認的編碼表,

3,該類中有臨時緩沖。

構造函數:在寫入流對象初始化時,必須要有一個存儲數據的目的地。

對于讀取或者寫入流對象的構造函數,以及讀寫方法,還有刷新關閉功能都會拋出IOException或其子類。所以都要進行處理。或者throws拋出,或者try?catch處理

另一個小細節:

當指定絕對路徑時,定義目錄分隔符有兩種方式:

1,反斜線但是一定要寫兩個。\\new?FileWriter("c:\\demo.txt");

2,斜線/??寫一個即可。new?FileWriter("c:/demo.txt");

一個讀取文本文件的經典例子:

[java]?view plaincopy
print?
  1. <span?style="color:#000000;">FileReader?fr?=?null;??
  2. try??
  3. {??
  4. fr?=?new?FileReader("demo.txt");??
  5. char[]?buf?=?new?char[1024];//該長度通常都是1024的整數倍。??
  6. int?len?=?0;??
  7. while((len=fr.read(buf))!=-1)??
  8. {??
  9. System.out.println(new?String(buf,0,len));??
  10. }??
  11. }??
  12. catch(IOException?e)??
  13. {??
  14. System.out.println(e.toString());??
  15. }??
  16. </span>??


字符流的緩沖區:緩沖區的出現提高了對流的操作效率。

原理:其實就是將數組進行封裝。

對應的對象:

BufferedWriter:特有方法:newLine():跨平臺的換行符。

BufferedReader:特有方法:readLine():一次讀一行,到行標記時,將行標記之前的字符數據作為字符串返回。當讀到末尾時,返回null。

在使用緩沖區對象時,要明確,緩沖的存在是為了增強流的功能而存在,

所以在建立緩沖區對象時,要先有流對象存在。

其實緩沖內部就是在使用流對象的方法,只不過加入了數組對數據進行了臨時存儲。為了提高操作數據的效率。

代碼上的體現:

寫入緩沖區對象。

//建立緩沖區對象必須把流對象作為參數傳遞給緩沖區的構造函數。

BufferedWriter?bufw?=?new?BufferedWriter(new?FileWriter("buf.txt"));

bufw.write("abce");//將數據寫入到了緩沖區。

bufw.flush();//對緩沖區的數據進行刷新。將數據刷到目的地中。

bufw.close();//關閉緩沖區,其實關閉的是被包裝在內部的流對象。

讀取緩沖區對象。

BufferedReader?bufr?=?new?BufferedReader(new?FileReader("buf.txt"));

String?line?=?null;

//按照行的形式取出數據。取出的每一個行數據不包含回車符。

while((line=bufr.readLine())!=null)

{

System.out.println(line);

}

bufr.close();

readLine():方法的原理:

其實緩沖區中的該方法,用的還是與緩沖區關聯的流對象的read方法。只不過,每一次讀到一個字符,先不進行具體操作,先進行臨時存儲。當讀取到回車標記時,將臨時容器中存儲的數據一次性返回。

既然明確了原理,我們也可以實現一個類似功能的方法。

[java]?view plaincopy
print?
  1. class?MyBufferedReader??
  2. {??
  3. private?Reader?r;??
  4. MyBufferedReader(Reader?r)??
  5. {??
  6. this.r?=?r;??
  7. }??
  8. public?String?myReadLine()throws?IOException??
  9. {//1,創建臨時容器。??
  10. StringBuilder?sb?=?new?StringBuilder();??
  11. //2,循環的使用read方法不斷讀取字符。??
  12. int?ch?=?0;??
  13. while((ch=r.read())!=-1)??
  14. {??
  15. if(ch=='\r')??
  16. continue;??
  17. if(ch=='\n')??
  18. return?sb.toString();??
  19. else??
  20. sb.append((char)ch);??
  21. }??
  22. if(sb.length()!=0)??
  23. return?sb.toString();??
  24. return?null;??
  25. }??
  26. public?void?myClose()throws?IOException??
  27. {??
  28. r.close();??
  29. }??
  30. }??


然后說一下字節流:

抽象基類:InputStream,OutputStream。

字節流可以操作任何數據。

注意:字符流使用的數組是字符數組。char?[]?chs字節流使用的數組是字節數組。byte?[]?bt

FileOutputStream?fos?=?new?FileOutputStream("a.txt");

fos.write("abcde");//直接將數據寫入到了目的地。

fos.close();//只關閉資源。

FileInputStream?fis?=?new?FileInputStream("a.txt");

//fis.available();//獲取關聯的文件的字節數。

//如果文件體積不是很大。

//可以這樣操作。

byte[]?buf?=?new?byte[fis.available()];//創建一個剛剛好的緩沖區。

//但是這有一個弊端,就是文件過大,大小超出jvm的內容空間時,會內存溢出。

?????fis.read(buf);

?????一個小問題:

字節流的read()方法讀取一個字節。為什么返回的不是byte類型,而是int類型呢?

因為read方法讀到末尾時返回的是-1,而在所操作的數據中的很容易出現連續多個1的情況,而連續讀到8個1,就是-1,導致讀取會提前停止。所以將讀到的一個字節給提升為一個int類型的數值,但是只保留原字節,并在剩余二進制位補0.

對于write方法,可以一次寫入一個字節,但接收的是一個int類型數值。只寫入該int類型的數值的最低一個字節(8位)。

簡單說:read方法對讀到的數據進行提升。write對操作的數據進行轉換。這是神馬意思???

轉換流:

特點:

1,是字節流和字符流之間的橋梁。

2,該流對象中可以對讀取到的字節數據進行指定編碼表的編碼轉換。

什么時候使用呢?

1,當字節和字符之間有轉換動作時。

2,流操作的數據需要進行編碼表的指定時。

具體的對象體現:

1,InputStreamReader:字節到字符的橋梁。

2,OutputStreamWriter:字符到字節的橋梁。

這兩個流對象是字符流體系中的成員。

那么它們有轉換作用,而本身又是字符流。所以在構造的時候,需要傳入字節流對象進來。

構造函數:

InputStreamReader(InputStream):通過該構造函數初始化,使用的是本系統默認的編碼表GBK。

InputStreamReader(InputStream,String?charSet):通過該構造函數初始化,可以指定編碼表。

OutputStreamWriter(OutputStream):通過該構造函數初始化,使用的是本系統默認的編碼表GBK。

OutputStreamWriter(OutputStream,String?charSet):通過該構造函數初始化,可以指定編碼表。

可以和流相關聯的集合對象Properties.

Map

??|--Hashtable

?????|--Properties

Properties:該集合不需要泛型,因為該集合中的鍵值對都是String類型。

1,存入鍵值對:setProperty(key,value);

2,獲取指定鍵對應的值:value?getProperty(key);

3,獲取集合中所有鍵元素:

Enumeration??propertyNames();

在jdk1.6版本給該類提供一個新的方法。

Set<String>?stringPropertyNames();

4,列出該集合中的所有鍵值對,可以通過參數打印流指定列出到的目的地。

list(PrintStream);

list(PrintWriter);

例:list(System.out):將集合中的鍵值對打印到控制臺。

list(new?PrintStream("prop.txt")):將集合中的鍵值對存儲到prop.txt文件中。

5,可以將流中的規則數據加載進行集合,并稱為鍵值對。

load(InputStream):

jdk1.6版本。提供了新的方法。

load(Reader):

注意:流中的數據要是"鍵=值"?的規則數據。

6,可以將集合中的數據進行指定目的的存儲。

store(OutputStram,String?comment)方法。

jdk1.6版本。提供了新的方法。

store(Writer?,String?comment):

使用該方法存儲時,會帶著當時存儲的時間。

File類:

該類的出現是對文件系統的中的文件以及文件夾進行對象的封裝。

可以通過對象的思想來操作文件以及文件夾。

1,構造函數:

File(String?filename):將一個字符串路徑(相對或者絕對)封裝成File對象,該路徑是可存在的,也可以是不存在。

File(String?parent,String?child);

File(File?parent,String?child);

2,特別的字段:separator:跨平臺的目錄分隔符。

如:File?file?=?new?File("c:"+File.separator+"abc"+File.separator+"a.txt");

3,常見方法:

1,創建:

boolean?createNewFile()throws?IOException:創建文件,如果被創建的文件已經存在,則不創建。

boolean?mkdir():?創建文件夾。

boolean?mkdirs():?創建多級文件夾。

2,刪除:

boolean?delete():可用于刪除文件或者文件夾。

注意:對于文件夾只能刪除不帶內容的空文件夾,

對于帶有內容的文件夾,不可以直接刪除,必須要從里往外刪除。

void?deleteOnExit():?刪除動作交給系統完成。無論是否反生異常,系統在退出時執行刪除動作。

3,判斷:

boolean?canExecute():

boolean?canWrite():

boolean?canRead();

boolean?exists():判斷文件或者文件夾是否存在。

boolean?isFile():?判斷File對象中封裝的是否是文件。

boolean?isDirectory():判斷File對象中封裝的是否是文件夾。

boolean?isHidden():判斷文件或者文件夾是否隱藏。在獲取硬盤文件或者文件夾時,

對于系統目錄中的文件,Java是無法訪問的,所以在遍歷,可以避免遍歷隱藏文件。

4,獲取:

getName():獲取文件或者文件夾的名稱。

getPath():File對象中封裝的路徑是什么,獲取的就是什么。

getAbsolutePath():無論File對象中封裝的路徑是什么,獲取的都是絕對路徑。

getParent():?獲取File對象封裝文件或者文件夾的父目錄。

注意:如果封裝的是相對路徑,那么返回的是null.

long?length():獲取文件大小。

longlastModified():獲取文件或者文件最后一次修改的時間。

static?File[]?listRoots():獲取的是被系統中有效的盤符。

String[]?list():獲取指定目錄下當前的文件以及文件夾名稱。

String[]?list(Filenamefilter):?可以根據指定的過濾器,過濾后的文件及文件夾名稱。

File[]?listFiles():獲取指定目錄下的文件以及文件夾對象。

5,重命名:

renameTo(File):

File?f1?=?new?File("c:\\a.txt");

File?f2?=?new?File("c:\\b.txt");

f1.renameTo(f2);//將c盤下的a.txt文件改名為b.txt文件。

對象的序列化。

ObjectInputStream

ObjectOutputStream

可以通過這兩個流對象直接操作已有對象并將對象進行本地持久化存儲。

存儲后的對象可以進行網絡傳輸。

Serializable:該接口其實就是一個沒有方法的標記接口。

用于給類指定一個UID。該UID是通過類中的可序列化成員的數字簽名運算出來的一個long型的值。

只要是這些成員沒有變化,那么該值每次運算都一樣。

該值用于判斷被序列化的對象和類文件是否兼容。

如果被序列化的對象需要被不同的類版本所兼容。可以在類中自定義UID。

定義方式:static?final?long?serialVersionUID?=?42L;

注意:對應靜態的成員變量,不會被序列化。

對應非靜態也不想被序列化的成員而言,可以通過transient關鍵字修飾。

通常,這兩個對象成對使用。

————————————————————————————————————

其他的數據操作流

操作基本數據類型的流對象。

DataInputStream

DataInputStream(InputStream);

操作基本數據類型的方法:

int?readInt():一次讀取四個字節,并將其轉成int值。

boolean?readBoolean():一次讀取一個字節。

short?readShort();

long?readLong();

剩下的數據類型一樣。

String?readUTF():按照utf-8修改版讀取字符。注意,它只能讀writeUTF()寫入的字符數據。

DataOutputStream

DataOutputStream(OutputStream):

操作基本數據類型的方法:

writeInt(int):一次寫入四個字節。

注意和write(int)不同。write(int)只將該整數的最低一個8位寫入。剩余三個8位丟棄。

writeBoolean(boolean);

writeShort(short);

writeLong(long);

剩下是數據類型也也一樣。

writeUTF(String):按照utf-8修改版將字符數據進行存儲。只能通過readUTF讀取。

通常只要操作基本數據類型的數據。就需要通過DataStram進行包裝。

通常成對使用。

————————————————————————————————————

操作數組的流對象。

1,操作字節數組

ByteArrayInputStream

ByteArrayOutputStream

toByteArray();

toString();

writeTo(OutputStream);

2,操作字符數組。

CharArrayReader

CharArrayWriter

對于這些流,源是內存。目的也是內存。

而且這些流并未調用系統資源。使用的就是內存中的數組。

所以這些在使用的時候不需要close。

操作數組的讀取流在構造時,必須要明確一個數據源。所以要傳入相對應的數組。

對于操作數組的寫入流,在構造函數可以使用空參數。因為它內置了一個可變長度數組作為緩沖區。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/451914.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/451914.shtml
英文地址,請注明出處:http://en.pswp.cn/news/451914.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot入門(9)網頁版計算器

介紹 在寫了前八篇Spring Boot項目的介紹文章后&#xff0c;我們已經初步熟悉了利用Spring Boot來做Web應用和數據庫的使用方法了&#xff0c;但是這些僅僅是官方介紹的一個例子而已。 ??本次分享將介紹筆者自己的一個項目&#xff1a;網頁版計算器&#xff0c;以這兩篇博客…

shell編程基礎(七): 處理文件命令sed與awk

一、sed&#xff08;以行為單位處理文件&#xff09; sed意為流編輯器&#xff08;Stream Editor&#xff09;&#xff0c;在Shell腳本和Makefile中作為過濾器使用非常普遍&#xff0c;也就是把前一個程序的輸出引入sed的輸入&#xff0c;經過一系列編輯命令轉換為另一種格式輸…

數據結構與算法--6.二分查找

文章目錄一. 二分查找二. 代碼實現一&#xff1a;使用遞歸三. 代碼實現二&#xff1a;非遞歸一. 二分查找 二. 代碼實現一&#xff1a;使用遞歸 def binary_search(alist, item):"""二分查找&#xff1a;使用遞歸"""n len(alist)if n > 0:m…

SpringMVC請求處理流程、springMVC工作流程

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 頁面請求到來 --> 前端控制器&#xff08;DispatcherServlet&#xff09;收到請求&#xff0c;請求 處理映射器&#xff08;Hanle…

Android的TextView在顯示文字的時候,如果有段中文有英文,有中文,有中文標點符號,你會發現,當要換行的時候遇到中文標點, 這一行就會空出很多空格出來...

一、問題描述&#xff1a; Android的TextView在顯示文字的時候&#xff0c;如果有段中文有英文&#xff0c;有中文&#xff0c;有中文標點符號&#xff0c;你會發現&#xff0c;當要換行的時候遇到中文標點&#xff0c; 這一行就會空出很多空格出來。原因是&#xff1a; 1&…

什么是IDE

集成開發環境&#xff08;IDE&#xff0c;Integrated Development Environment &#xff09;是用于提供程序開發環境的應用程序&#xff0c;一般包括代碼編輯器、編譯器、調試器和圖形用戶界面等工具。集成了代碼編寫功能、分析功能、編譯功能、調試功能等一體化的開發軟件服務…

vue 學習

http://jspang.com/ vue 學習 vue 學習 轉載于:https://www.cnblogs.com/qianjin888/p/9342031.html

策略模式-Strategy Pattern

解決問題 將算法按照策略或場景封裝起來&#xff0c;以方便按照不同的場景執行不同的策略。它很好的解決了通過if...else 來決策行為而帶來的代碼和邏輯復雜性。 應用場景 一個經常被拿來舉例的場景是收銀員收銀場景&#xff1a;它需要根據不同的場景&#xff08;是否為會員、有…

ssm框架下 tiles框架 的使用

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 tiles框架的工作 在springMVC工作流程中屬于視圖解析器 解析視圖這一步。算是視圖解析器的一個插件&#xff0c;作了視圖解析這步的一部…

數據結構與算法--7.樹的基礎知識

文章目錄一. 樹的概念二. 樹的術語三. 樹的種類四. 樹的存儲和表示五. 常見的樹的應用場景一. 樹的概念 二. 樹的術語 三. 樹的種類 四. 樹的存儲和表示 五. 常見的樹的應用場景

運用java 多線程模擬火車售票。。。。

public class Demo01 { public static void main(String[] args) { // TODO Auto-generated method stub //多線程并行時&#xff0c;會出現的問題 //同步&#xff1a; //買火車票&#xff0c;四個窗口A,B,C,D //創建任務 TicketTask task new TicketTask(); //四個窗口A,B,C,…

JQuery validate 各項驗證規則講解

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 使用樣例見&#xff1a;http://blog.csdn.net/jiangyu1013/article/details/56014730 //定義中文消息 var cnmsg { required: “必選字…

數據結構與算法--8.二叉樹的基礎知識

文章目錄一. 二叉樹基本概念二. 二叉樹的性質三. 二叉樹的代碼實現四. 二叉樹的先序、中序、后序遍歷一. 二叉樹基本概念 二. 二叉樹的性質 三. 二叉樹的代碼實現 class Node(object):"""二叉樹節點"""def __init__(self,item):self.elem item…

ZooKeeper(二)ZooKeeper能做什么?

上一節介紹了ZooKeeper的一些基礎知識&#xff0c;這一節主要講ZooKeeper有哪些用途。命名服務&#xff08;Name Service&#xff09; 主要是作為分布式命名服務&#xff0c;通過調用zk的create node api&#xff0c;能夠很容易創建一個全局唯一的path&#xff0c;這個path就可…

jquery vilidate 使用小例

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 // 修改$("#updForm").validate({submitHandler:function(form){new $.flavr({ content : 是否確認修改管理員?,dialog : co…

RedHat Linux 7.3基礎環境搭建

文章目錄1&#xff0e;更改主機名2&#xff0e;關閉selinux3&#xff0e;關閉火墻4&#xff0e;重啟機器5&#xff0e;設置ip6&#xff0e;掛載yum源7&#xff0e;升級openssh8&#xff0e;安全基線9&#xff0e;時區10&#xff0e;時間同步11&#xff0e;安裝Vmtools12&#x…