-------android培訓、java培訓、java學習型技術博客、期待與您交流! ----------
知識點二 字節流
一、概述:
1、字節流的操作原理和字符流類是相似的,只不過字節流可以對圖片、音頻和視頻媒體進行操作。
2、由於媒體數據中都是以字節存儲的,所以,字節流對象可直接對媒體進行操作,可以不用再進行刷新流的動作。
3、讀寫字節流:InputStream ---> 輸入流(讀)
OutputStream ---> 輸出流(寫)
4、不用進行刷新流的動作的原因:
因爲字節流操作的是字節,即數據的最小單位,不需要像字符流一樣要進行轉換爲字節。可直接將字節寫入到指定文件中,但是需要在寫代碼的時候,如果有字符串,要將字符串轉爲字節數組再進行操作。
5、字節流所特有方法:
int available() ---> 放回數據字節的長度,包含終止符
在定義字節數組長度的時候,可以用到這個方法:byte[] = new byte[fos.available()] (fos爲字節流對象)
但是,對於這個方法要慎用,如果字節過大,比如一部電影(幾個G),那麼如此大的數組就會損壞內存,超過jvm所承受的大小(指定內存爲64M)。
舉例:
/*
字符流:
FileReader
FileWriter
BufferedReader
BufferedWriter
字節流:
兩個基類:
InputStream(讀) OutputStream(寫)
需求:想要操作圖片數據,這時候就要用到字節流
*/
import java.io.*;
class FileStream{
public static void main(String []args) throws IOException
{
// writeFile();
// readFile_1();
// readFile_2();
readFile_3();
}
public static void readFile_1() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");
int ch=0;
while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}
fis.close();
}
public static void readFile_2() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");
//以這種方式爲主,這是最好,最優化的方式
byte[] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
fis.close();
}
public static void readFile_3() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");
// int num=fis.available();
//這種方式要慎用,數據不是太大的話,可以這樣使用
byte[] buf=new byte[fis.available()];//定義一個剛剛好的緩衝區,不用再循環了
fis.read(buf);
// System.out.println("num="+num);
System.out.println(new String(buf));
fis.close();
}
public static void writeFile() throws IOException
{
FileOutputStream fos=new FileOutputStream("fos.txt");
//將字符串變爲字節數組
fos.write("abcde".getBytes());
fos.close();
}
}
二、複製媒體文件(一張圖片):
1、思路:
1)用字節流讀取流對象和媒體文件相關聯
2)用字節寫入流對象,創建一個媒體文件,用於存儲獲取到的媒體文件數據
3)通過循環讀寫,完成數據的存儲
4)關閉資源
注意:不要用字符流操作媒體文件,因爲圖片數據讀取一段後去查編碼表,如果找到對應的數字編碼未變話,如果沒找到去找編碼表的未知區域,所以編碼會發生變化,這樣生成新圖片的編碼和老圖片的編碼就不一樣了,字節碼發生變化,因此字符流只用於處理文字數據。
示例:
import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("c:\\2.bmp");
fis = new FileInputStream("c:\\1.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("複製文件失敗");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("讀取關閉失敗");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("寫入關閉失敗");
}
}
}
}
三、字節流緩衝區:
1、讀寫特點:
read():會將字節byte型值提升爲int型值
write():會將int型強轉爲byte型,即保留二進制數的最後八位。
2、原理:將數據拷貝一部分,讀取一部分,循環,直到數據全部讀取完畢。
1)先從數據中抓取固定數組長度的字節,存入定義的數組中,再通過然後再通過read()方法讀取數組中的元素,存入緩衝區
2)循環這個動作,知道最後取出一組數據存入數組,可能數組並未填滿,同樣也取出包含的元素
3)每次取出的時候,都有一個指針在移動,取到數組結尾就自動回到數組頭部,這樣指針在自增
4)取出的時候,數組中的元素再減少,取出一個,就減少一個,直到減到0即數組取完
5)到了文件的結尾處,存入最後一組數據,當取完數組中的元素,就會減少到0,這是全部數據就取完了
示例:
/*
通過緩衝區,演示Mp3的複製
BufferedOutputStream
BufferedInputStream
*/
import java.io.*;
class CopyMp3{
public static void main(String []args) throws IOException
{
long start=System.currentTimeMillis();
//copy_1();
copy_2();
long end=System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
//通過字節流的緩衝區,完成複製
public static void copy_1() throws IOException
{
//緩衝區裏已經定義了數組
BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("C:\\0.mp3"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\1.mp3"));
int by=0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
public static void copy_2() throws IOException
{
MyBufferedInputStream bufis=new MyBufferedInputStream(new FileInputStream("C:\\0.mp3"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\2.mp3"));
int by=0;
//讀了一次沒有寫出去
// System.out.println("第一個字節:"+bufis.myRead());
while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
}
4、自定義字節流緩衝區:
思路:
1、定義一個固定長度的數組
2、定義一個指針和計數器用於讀取數組長度,和計數數組元素是否取完爲0
3、每次將字節數據存入元素要先將數組中的元素取完
注:取出的是byte型,返回的是int型,這裏存在提升的動作,
當byte中的八位全爲1的時候是byte的-1,提升爲int類型,就變爲int型的-1,,read循環條件就結束了
變爲-1的原因是由於在提升時,將byte的八位前都補的是1,即32位的數都是1,即爲int型的-1了。
如何保證提升後的最後八位仍爲1呢?就需要將前24位補0,就可以保留原字節數據不變,又可以避免轉爲int型出現-1的情況;
那麼要如何做呢?
示例:
/*
11111111 -->提升了一個int類型,那不還是-1,嗎?是-1的原因是因爲在8個1的前面補得的是1導致的
那麼我只要在前面補0,既可以保留原字節數據不變,又可以避免-1的出現,那麼怎,補0呢
11111111 11111111 11111111 11111111
&00000000 00000000 00000000 11111111
-------------------------------------
00000000 00000000 00000000 11111111
這樣就可以避免-1的發生
byte:-1 ---->int:-1
read方法在提升,write方法將指定的字節寫入此緩衝的輸出流(強制轉換,取最低的8位)
*/
import java.io.*;
class MyBufferedInputStream{
private InputStream in;
private byte[] buf=new byte[1024*4];
private int pos=0;
private int count=0;
MyBufferedInputStream(InputStream in)
{
this.in=in;
}
//一次讀一個字節,從緩衝區(字節數組)獲取
public int myRead() throws IOException
{
//通過in對象,讀取硬盤上的數據,並存儲到buf中
if(count==0)
{
count= in.read(buf);
if(count<0)
return -1;
pos = 0;
//取數組第一個元素pos=0;
byte b=buf[pos];
count--;
pos++;
//b與255進行與操作,用十六進制表示就是0xff
return b&255;
}else if(count>0)
{
byte b=buf[pos];
count--;
pos++;
//b與255進行與操作,用十六進制表示就是0xff
return b&255;
}
return -1;
}
public void myClose()throws IOException
{
in.close();
}
}
5.讀取鍵盤錄入
System.out:對應的是標準的輸出設備,控制檯。
System.in:對應的標準輸入設備,鍵盤
/*
需求:
通過鍵盤錄入數據,當錄入一行數據後就進行打印。
如果當錄入的數據時over,那麼停止錄入
Dos下鍵盤錄入操作終止可以使用Ctrl+C操作
*/
import java.io.*;
class ReadIn
{
public static void main(String[] args) throws IOException
{
InputStream in=System.in;
StringBuilder sb=new StringBuilder();
/*
int ch=0;
while((ch=in.read())!=-1)
{
System.out.println(ch);
}
*/
while(true)
{
int ch=in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
String s=sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
//sb=new StringBuilder();
sb.delete(0,sb.length());
}
else
sb.append((char)ch);
}
in.close();
//數據類型轉換
System.out.println('\r'+0);
System.out.println('\n'+0);
/*
int by=in.read();
int by1=in.read();
int by2=in.read();
System.out.println(by);
System.out.println(by1);
System.out.println(by2);
*/
}
}
知識點三 轉換流
一、概述:
轉換流的由來:內部可以指定編碼表
1.通過上面的示例,通過鍵盤錄入一行數據並打印其大寫,發現其實就是讀一行數據的原理
能不能直接使用readLine方法來完成鍵盤錄入的一行數據的讀取呢?
readLine方法是字符流BufferedReader類中的方法
而鍵盤錄入的read方法字節流InputStream的方法
那麼能不能將字節流轉成字符流在使用字符流緩衝區的readLine方法呢?
2.兩個轉換流:讀取轉換流InputStreamReader和寫入轉換流OutputStreamWriter,這兩個類分別屬於字符流Reade和Writer的子類
二、讀取轉換流:
InputStreamReader是字節流通向字符流的橋樑,它使用指定的charset讀取字節並將其解碼爲字符。
InputStreamReader:讀取轉換流
a.獲取鍵盤錄入對象: ---> InputStream in = System.in;
b.將字節流對象轉換成字符流對象,使用轉換流InputStreamReader: ---> InputStreamReader isr = new InputStreamReader(in);
c.爲提高效率,將字符串進行緩衝區技術操作,使用BufferedReader: ---> BufferedReader bufw = new BufferedReader(isr);
d.之後就可以使用readLine()方法讀取錄入的一行數據了。
示例:
class TransStreamDemo{
public static void main(String []args) throws IOException
{
//獲取鍵盤錄入對象
// InputStream in=System.in;
//將字節流對象裝換成字符流對象,InputStreamReader
//InputStreamReader isr=new InputStreamReader(in);
//爲了提高效率,講將字符流進行緩衝區技術的高效操作
// BufferedReader bufr=new BufferedReader(isr);
BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("CopyMp3.java")));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
bufr.close();
}
}
OutputStreamWriter是字符流通向字節流的橋樑,可使用指定的charset將要寫入流中的字符編碼成字節。
OutputStreamWriter:寫入轉換流 ---> 和讀取轉換流同理,即使用對應的Writer的子類
示例:
class TransStreamDemo{
public static void main(String []args) throws IOException
{
//*************畢老師說這句換一定要記住,鍵盤錄入,非常的重要********************
//鍵盤錄入最常見寫法
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
知識點四 流操作規律
一、分析清楚源和目的以及需求:
1.源:鍵盤錄入
目的:控制檯
2.需求:想把鍵盤錄入的數據存儲到一個文件中
源:鍵盤
目的:文件
3.需求:想要將一個文件的數據打印在控制檯上。
源:文件
目的:控制檯
二:流操作的基本規律:
最痛苦的就是流對象有很多,不知道該用哪一個
通過三個來明確
1.明確源和目的
源:輸入流 InputStream Reader
目的:輸出流 OutputStream Writer
2.明確操作的數據是否是純文本
是:字符流
不是:字節流
3.當體系明確後,在明確要使用哪個具體的對象
通過設備來進行區分;
源設備:內存(ArrayStream),硬盤(FileStream),鍵盤(System.in)
目的設備:內存(ArrayStream),硬盤(FileStream),控制檯(System.out)。
4、需求體現:
4.1需求:將一個文本文件中的數據存儲到另一個文件中,複製文件。
源:因爲是源,所以使用讀取流 InputStream Reader
是不是操作文本文件?
是!這時就可以選擇Reader
這樣體系就明確了
接下來明確對象該體系中的哪個對象。
明確設備:硬盤上的一個文件。
Reader體系中可以操作文件的對象是FileReader
是否需要提高效率:是!加入Reader體系中的緩衝區,BufferedReader
FileReader fr=new FileReader("a.txt");
BufferReader bufr=new BufferedReader(fr);
目的:OutputStream Writer
是否是純文本文件?
是!Writer。
設備:硬盤。一個文件。
Writer體系中可以操作文件的對象是FileWriter
是否需要提高效率:是!加入Writer體系中的緩衝區,BufferedWriter
FileWriter fw=new FileWriter("b.txt");
BufferedWriter bufw=new BufferedWriter(fw);
練習:將一個圖片文件中數據存儲到另一個文件中,複製文件。要按照以上格式完成三個明確。
分析:
1)源:InputStream和Reader
圖片:字節流 ---> InputStream
設備:硬盤上的文件 ---> FileInputStream
2)目的:OutoutStream和Writer
圖片:字節流 ---> OutputStream
設備:硬盤上的文件 ---> FileOutputStream
4.2需求:將鍵盤錄入的數據保存到一個文件中
這個需求中有源和目的都存在。
那麼分別分析
源:InputStream Reader
是不是純文本?是!Reader
設備:鍵盤。對應的對象是System.in
不是選擇Reader嗎?System.in對應的不是字節流嗎?
爲了操作鍵盤的文本數據方便。轉成字符流按照字符串操作是最方便的。
所以既然明確了Reader,那麼就將System.in裝換成Reader。
用了Reader體系中的轉換流,InputStreamReader
InputStreamReader isr=new InputStreamReader(System.in);
//需要提高效率嗎?需要BufferedReader
BufferedReader bufr=new BufferedReader(isr);
目的:OutputputStream Writer
是否是純文本?是!Writer
設備:硬盤。一個文件。使用FileWriter
FileWriter fw=new FileWriter("c.txt");
需要提高效率嗎?需要
BufferedWriter bufw=new BufferedWriter(fw);
5.擴展一下,想要把錄入的數據按照指定的編碼表(utf-8),將數據存到文件中
class TransStreamDemo2{
public static void main(String []args) throws IOException
{
//獲取鍵盤錄入對象
// InputStream in=System.in;
//鍵盤錄入最常見寫法
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d2.txt"),"UTF-8"));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
6.改變標準輸入輸出設備System.setIn(new FileInputStream("PersonDemo.java"));
System.setOut(new PrintStream("zz.txt"));
一、異常的日誌信息:
當程序在執行的時候,出現的問題是不希望直接打印給用戶看的,是需要作爲文件存儲起來,方便程序員查看,並及時調整的。
示例:/*
說明:Log4j的jar包可以完成日誌信息建立
*/
import java.io.*;
import java.util.*;
//格式化要用的包
import java.text.*;
class ExceptionInfo
{
public static void main(String[] args) throws IOException
{
try{
int[] arr=new int [2];
System.out.println(arr[3]);
}catch(Exception e)
{
try{
//打印日期
Date d=new Date();
//SimpleDateFormat將時間格式化
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//h是12小時制,H是24小時制
String s=sdf.format(d);
PrintStream ps=new PrintStream("exception.log");
//ps是字節流,要將字符串變成字節數組寫出去
//ps.write(d.toString().getBytes);
//ps.println(d.toString());
ps.println(s);
//改變標準輸出
System.setOut(ps);
//e.printStackTrace(new PrintStream("a.txt"));
}catch(IOException ex)
{
throw new RuntimeException("日誌文件創建失敗");
}
e.printStackTrace(System.out);
}
}
}
二、系統信息:
獲取系統信息:Properties getProperties()
將信息輸出到指定輸出流中
void list(PrintStream out)
將輸出流中數據存入指定文件中
new PrintStream("systeminfo.txt")
import java.io.*;
import java.util.*;
class SystemInfo
{
public static void main(String[] args) throws IOException
{
//打印系統信息
//源就是集合中的數據也就是內存
Properties prop=System.getProperties();
//System.out.println(prop);
//將系統信息打印在控制檯上
//prop.list(System.out);
prop.list(new PrintStream("sysinfo.txt"));
}
}
最新最全的的java學習視頻教程:http://pro.net.itcast.cn/View-22-1458.aspx