java輸入與輸出流
概述
從14年10月份開始工作,到今天做Android已經兩年半了。可是到現在也沒搞清楚Java的I/O機制,痛定思痛,覺得好好整理一下。古人云“格物致知”,今天就好好格一格I/O機制吧!
常見問題
什麼是流
“流”是一連串流動的字元,同時也說明了資料傳輸的一種狀態:“均勻與連續”。java使用“流”進行資料傳輸。而傳輸的雙方一般是“你的程式”和“裝置(手機)”。
輸入和輸出流
根據流的方向,可以分為輸入流和輸出流。流的輸入(Input)和輸出(Output)是以應用程式為參考中心的。輸入流就是從裝置流入到應用程式,也即常說的讀(Read);輸出流就是從應用程式流到裝置,也即我們常說的寫(Write)。
原理圖如下:
注:輸入流命名規則是包含Input或Reader,如InputStream、BufferedReader;輸出流命名規則是包含Output或Writer,如OutputStream、BufferedWriter。
位元組流和字元流
資料傳輸的基本單位是位元組(bytes),但1個位元組是8位,表示範圍是0-255。面對諸多漢字,1個位元組很明顯是不足的。所以生成了一種新的單位:字元,而字元和位元組之間的對映關係就是Unicode。在java中1個字元等於2個位元組。根據流的資料型別,可分為位元組流和和字元流。
位元組流和字元流的區別
1. 讀寫單位:位元組流處理的基本單元是位元組;字元流處理的基本單元是Unicode碼,2個位元組
2. 處理物件:位元組流能處理所有型別的資料(圖片,視訊,音訊等),字元流只能處理字元型資料(字串,純文字文件)
3. 是否快取:字元流傳輸之前要先經過Unicode轉換成位元組流,批量轉換後的位元組流儲存到快取當中(提示效率),然後再進行讀寫。位元組流則不用快取(位元組流本身是不使用位元組流的,但是如果想提升效率,可以自定義快取區)。
注:位元組流一般命名規則是以Stream結尾,如InputStream或OutputStream;字元流一般命名規則是以Reader或Writer結尾。如BufferedReader、BufferedWriter。
節點和處理流
根據流是否直接與資料來源相連,可以劃分為節點流和處理流。節點流是可以直接從/向資料來源(裝置,硬碟,記憶體等)讀/寫資料;處理流是對一個已存在的流的連線、封裝和處理。
注:處理流命名規則是包含buffered,如BufferedInputStream、BufferedReader。
介紹
I/O家族譜系
根據操作的資料型別,分為位元組流和字元流;根據資料的流向,又分為輸入流和輸出流;根據功能,分為節點流和處理流。
InputStream和OutputStream
位元組流處理的抽象基類是InputStream和OutputStream。InputStream是位元組輸入流,OutputStream是位元組輸出流。
Reader和Writer
字元流處理的抽象基類是Reader和Writer。Reader是字元輸入流,Writer是字元輸出流。
實戰演示
介紹的差不多了,接下來就是實戰演示了。
1.從本地讀取圖片
1. 讀取說明資料流是從裝置到應用,因此使用輸入流,那就是InputStream或Reader
2. 操作的資料物件是圖片,使用位元組流的話效率較高(不用經由Unicode轉換)
3. 所以排除Reader,選擇InputStream
public void readImg(ImageView iv) {
File file = new File("/sdcard/temp.jpg");
if (file.exists()) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
byte[] img = new byte[(int) file.length()];// 根據檔案長度建立位元組陣列
fileInputStream.read(img); // 將圖片位元組資訊寫入到位元組陣列
Bitmap bitmap = BitmapFactory.decodeByteArray(img,0,img.length);
iv.setImageBitmap(bitmap); // 顯示圖片
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.儲存圖片到本地
1. 儲存到本地說明資料流是從應用到裝置,因此使用輸出流,所以選擇OutputStream或Writer
2. 由於操作的資料物件是圖片,使用位元組流的話效率較高(不用經由Unicode轉換)
3. 所以排除Writer,選擇OutputStream
public void saveImg() {
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
try {
URL url = new URL("https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/image/h%3D360/sign=e572f27e9058d109dbe3afb4e158ccd0/b7fd5266d0160924933e331bd60735fae6cd3492.jpg");
URLConnection urlConnect = url.openConnection();
urlConnect.setConnectTimeout(5000);
inputStream = urlConnect.getInputStream();
File tempFile = new File("/sdcard/temp.jpg");// 儲存到臨時檔案中
if(tempFile.isDirectory()){
tempFile.delete();
}
if (!tempFile.exists()) {
tempFile.createNewFile();
}
fileOutputStream = new FileOutputStream(tempFile);// 建立輸出流,引數tempFile為寫入的目標
byte[] buffer = new byte[1024];
int length = -1;
while ((length = inputStream.read(buffer)) != -1) { // 讀取位元組,先儲存到快取區
fileOutputStream.write(buffer, 0, length); // 從快取區提取資料,可以提升效率
}
inputStream.close();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
3.從本地讀取純文件
1. 由於是讀取,說明資料流是從裝置流到應用,因此使用輸入流,所以選擇InputStream或Reader
2. 操作的資料物件是純文件,需要使用字元流(純文件需要經由Unicode轉碼)
3. 所以排除InputStream,選擇Reader
public String readWold() {
try {
FileReader fileReader = new FileReader("/sdcard/test.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = null;
StringBuilder builder = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
builder.append(line + "\n");
}
bufferedReader.close();
return builder.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
4.寫入到本地純文件
1.寫入說明資料流是從應用到裝置,因此使用輸出流,所以選擇OutputStream或Writer
2. 操作的資料物件是純文件,需要使用字元流(純文件或字串需要經由Unicode轉碼)
3. 所以排除OutputStream,選擇Writer
public void saveWord() {
try {
File file = new File("/sdcard/test.txt");
if (file.isDirectory()){
file.delete();
}
if (!file.exists()){
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("Hi,I am Chaos!");
bufferedWriter.newLine();
bufferedWriter.write("I am come from China!");
bufferedWriter.newLine();
bufferedWriter.flush();
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}