一、簡介
Java IO主要在java.io包下,分爲四大塊近80個類:
1、基於字節操作的I/O接口:InputStream和OutputStream
2、基於字符操作的I/O接口:Writer和Reader
3、基於磁盤操作的I/O接口:File
4、基於網絡操作的I/O接口:Socket(不在java.io包下)
影響IO性能的無非就是兩大因素:數據的格式及存儲的方式,前兩類主要是數據格式方面的,後兩個類是存儲方式方面的:本地和網絡。所以策劃好這兩個方面的活動,有助於我們合理使用IO。
IO流簡單來說就是Input和Output流,IO流主要是用來處理設備之間的數據傳輸,Java對於數據的操作都是通過流實現,而java用於操作流的對象都在IO包中。
分類:
Writer 按操作數據分爲:字節流和字符流。 如:Reader和InputStream
按流向分:輸入流和輸出流。如:InputStream和OutputStream
IO流常用的基類:
* InputStream , OutputStream
字符流的抽象基類:
* Reader , Writer
由上面四個類派生的子類名稱都是以其父類名作爲子類的後綴:
如:FileReader和FileInputStream
二、字符流Reader&Writer
1. 字符流簡介:
* 字符流中的對象融合了編碼表,也就是系統默認的編碼表。我們的系統一般都是GBK編碼。
* 字符流只用來處理文本數據,字節流用來處理媒體數據。
* 數據最常見的表現方式是文件,字符流用於操作文件的子類一般是FileReader和FileWriter。
2.字符流讀寫:
注意事項:
* 寫入文件後必須要用flush()刷新。
* 用完流後記得要關閉流
* 使用流對象要拋出IO異常
* 定義文件路徑時,可以用“/”或者“\\”。
* 在創建一個文件時,如果目錄下有同名文件將被覆蓋。
* 在讀取文件時,必須保證該文件已存在,否則出異常
示例1:在硬盤上創建一個文件,並寫入一些文字數據
class FireWriterDemo {
public static void main(String[] args) throws IOException { //需要對IO異常進行處理
//創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件。
//而且該文件會被創建到指定目錄下。如果該目錄有同名文件,那麼該文件將被覆蓋。
FileWriter fw = new FileWriter("F:\\1.txt");//目的是明確數據要存放的目的地。
//調用write的方法將字符串寫到流中
fw.write("hello world!");
//刷新流對象緩衝中的數據,將數據刷到目的地中
fw.flush();
//關閉流資源,但是關閉之前會刷新一次內部緩衝中的數據。當我們結束輸入時候,必須close();
fw.write("first_test");
fw.close();
//flush和close的區別:flush刷新後可以繼續輸入,close刷新後不能繼續輸入。
}
}
示例2:FileReader的reade()方法.
示例3:對已有文件的數據進行續寫要求:用單個字符和字符數組進行分別讀取
import java.io.*;
class FileWriterDemo3 {
public static void main(String[] args) {
try {
//傳遞一個參數,代表不覆蓋已有的數據。並在已有數據的末尾進行數據續寫
FileWriter fw = new FileWriter("F:\\java_Demo\\day9_24\\demo.txt",true);
fw.write(" is charactor table?");
fw.close();
}
catch (IOException e) {
sop(e.toString());
}
}
/**********************Println************************/
private static void sop(Object obj)
{
System.out.println(obj);
}
}
練習:
將F盤的一個文件複製到E盤。
思考:
其實就是將F盤下的文件數據存儲到D盤的一個文件中。
步驟:
1.在D盤創建一個文件,存儲F盤中文件的數據。
2.定義讀取流和F:盤文件關聯。
3.通過不斷讀寫完成數據存儲。
4.關閉資源。源碼:
import java.io.*;
import java.util.Scanner;
class CopyText {
public static void main(String[] args) throws IOException {
sop("請輸入要拷貝的文件的路徑:");
Scanner in = new Scanner(System.in);
String source = in.next();
sop("請輸入需要拷貝到那個位置的路徑以及生成的文件名:");
String destination = in.next();
in.close();
CopyTextDemo(source,destination);
}
/*****************文件Copy*********************/
private static void CopyTextDemo(String source,String destination) {
try {
FileWriter fw = new FileWriter(destination);
FileReader fr = new FileReader(source);
char [] buf = new char[1024];
//將Denmo中的文件讀取到buf數組中。
int num = 0;
while((num = fr.read(buf))!=-1) {
//String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
fw.write(new String(buf,0,num));
}
fr.close();
fw.close();
}
catch (IOException e) {
sop(e.toString());
}
}
/**********************Println************************/
private static void sop(Object obj) {
System.out.println(obj);
}
}
三、緩衝區
1. 字符流的緩衝區:BufferedReader和BufferedWreiter
* 緩衝區的出現時爲了提高流的操作效率而出現的.
* 需要被提高效率的流作爲參數傳遞給緩衝區的構造函數
* 在緩衝區中封裝了一個數組,存入數據後一次取出
BufferedReader示例:
讀取流緩衝區提供了一個一次讀一行的方法readline,方便對文本數據的獲取。
readline()只返回回車符前面的字符,不返回回車符。如果是複製的話,必須加入newLine(),寫入回車符newLine()是java提供的多平臺換行符寫入方法。
import java.io.*;
class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
//創建一個字符讀取流流對象,和文件關聯
FileReader rw = new FileReader("buf.txt");
//只要將需要被提高效率的流作爲參數傳遞給緩衝區的構造函數即可
BufferedReader brw = new BufferedReader(rw);
for(;;) {
String s = brw.readLine();
if(s==null) break;
System.out.println(s);
}
brw.close();//關閉輸入流對象
}
}
BufferedWriter示例:
import java.io.*;
class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//創建一個字符寫入流對象
FileWriter fw = new FileWriter("buf.txt");
//爲了提高字符寫入效率,加入了緩衝技術。
//只要將需要被提高效率的流作爲參數傳遞給緩衝區的構造函數即可
BufferedWriter bfw = new BufferedWriter(fw);
//bfw.write("abc\r\nde");
//bfw.newLine(); 這行代碼等價於bfw.write("\r\n"),相當於一個跨平臺的換行符
//用到緩衝區就必須要刷新
for(int x = 1; x < 5; x++) {
bfw.write("abc");
bfw.newLine(); //java提供了一個跨平臺的換行符newLine();
bfw.flush();
}
bfw.flush(); //刷新緩衝區
bfw.close(); //關閉緩衝區,但是必須要先刷新
//注意,關閉緩衝區就是在關閉緩衝中的流對象
fw.close(); //關閉輸入流對象
}
}
2.裝飾設計模式
裝飾設計模式::::
要求:自定義一些Reader類,讀取不同的數據(裝飾和繼承的區別)
MyReader //專門用於讀取數據的類
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
如果將他們抽取出來,設計一個MyBufferReader,可以根據傳入的類型進行增強
class MyBufferReader {
MyBufferReader (MyTextReader text) {}
MyBufferReader (MyMediaReader media) {}
MyBufferReader (MyDataReader data) {}
}
但是上面的類拓展性很差。找到其參數的共同類型,通過多態的形式,可以提高拓展性
class MyBufferReader extends MyReader{
private MyReader r; //從繼承變爲了組成模式 裝飾設計模式
MyBufferReader(MyReader r) {}
}
優化後的體系:
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader //增強上面三個。裝飾模式比繼承靈活,
避免繼承體系的臃腫。降低類與類之間的耦合性
裝飾類只能增強已有的對象,具備的功能是相同的。所以裝飾類和被裝飾類屬於同一個體系
MyBuffereReader類: 自己寫一個MyBuffereReader類,功能與BuffereReader相同
class MyBufferedReader1 extends Reader{
private Reader r;
MyBufferedReader1(Reader r){
this.r = r;
}
//一次讀一行數據的方法
public String myReaderline() throws IOException {
//定義一個臨時容器,原BufferReader封裝的是字符數組。
//爲了演示方便。定義一個StringBuilder容器。最終要將數據變成字符串
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch = r.read()) != -1)
{
if(ch == '\r')
continue;
if(ch == '\n') //遇到換行符\n,返回字符串
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0) //當最後一行不是以\n結束時候,這裏需要判斷
return sb.toString();
return null;
}
/*
需要覆蓋Reader中的抽象方法close(),read();
*/
public void close()throws IOException {
r.close();
}
public int read(char[] cbuf,int off, int len)throws IOException { //覆蓋read方法
return r.read(cbuf,off,len);
}
public void myClose() throws IOException{
r.close();
}
}
四、字節流
1.概述:
1、字節流和字符流的基本操作是相同的,但是要想操作媒體流就需要用到字節流。
2、字節流因爲操作的是字節,所以可以用來操作媒體文件。(媒體文件也是以字節存儲的)
3、讀寫字節流:InputStream 輸入流(讀)和OutputStream 輸出流(寫)
4、字節流操作可以不用刷新流操作。
5、InputStream特有方法:
int available();//返回文件中的字節個數
注:可以利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。但是如果文件較大,而虛擬機啓動分配的默認內存一般爲64M。當文件過大時,此數組長度所佔內存空間就會溢出。所以,此方法慎用,當文件不大時,可以使用。練習:
需求:複製一張圖片F:\java_Demo\day9_28\1.BMP到F:\java_Demo\day9_28\2.bmp
import java.io.*;
class CopyPic {
public static void main(String[] args){
copyBmp();
System.out.println("複製完成");
}
public static void copyBmp() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("F:\\java_Demo\\day9_28\\1.bmp"); //寫入流關聯文件
fos = new FileOutputStream("F:\\java_Demo\\day9_28\\2.bmp"); //讀取流關聯文件
byte[] copy = new byte[1024];
int len = 0;
while((len=fis.read(copy))!=-1) {
fos.write(copy,0,len);
}
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("複製文件異常");
}
finally {
try {
if(fis!=null) fis.close();
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("讀取流");
}
}
}
}
2. 字節流緩衝區
* 字節流緩衝區跟字符流緩衝區一樣,也是爲了提高效率。
注意事項:
1. read():會將字節byte()提升爲int型值
2. write():會將int類型轉換爲byte()類型,保留最後的8位。
練習:
1.複製MP3文件 1.MP3 --> 2.MP3
2.自己寫一個MyBufferedInputStream緩衝類,提升複製速度
代碼:
import java.io.*;
//自己的BufferedInputStream
class MyBufferedInputStream {
private InputStream in; //定義一個流對象
private byte [] buf = new byte[1024*4];
private int count = 0,pos = 0;
public MyBufferedInputStream(InputStream in){
this.in = in;
}
public int MyRead() throws IOException{
if(count==0) { //當數組裏的數據爲空時候,讀入數據
count = in.read(buf);
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b&255; //提升爲int類型,在前面三個字節補充0。避免1111 1111 1111 1111
}
else if(count > 0) {
byte b = buf[pos];
pos++;
count--;
return b&0xff; //提升爲int類型,在前面三個字節補充0。避免1111 1111 1111 1111
}
return -1;
}
public void myClose() throws IOException{
in.close();
}
}
class BufferedCopyDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
copy();
long end = System.currentTimeMillis();
System.out.println("時間:"+(end-start)+"ms");
start = System.currentTimeMillis();
copy1();
end = System.currentTimeMillis();
System.out.println("時間:"+(end-start)+"ms");
}
public static void copy1() { // 應用自己的緩衝區緩衝數據
MyBufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new MyBufferedInputStream(new FileInputStream("馬旭東-入戲太深.mp3"));//匿名類,傳入一個InputStream流對象
bos = new BufferedOutputStream(new FileOutputStream("3.mp3"));
int buf = 0;
while((buf=bis.MyRead())!=-1) {
bos.write(buf);
}
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("複製失敗");
}
finally {
try {
if(bis!=null) {
bis.myClose();
bos.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
五、流操作規律
1. 鍵盤讀取,控制檯打印。
System.out: 對應的標準輸出設備:控制檯 //它是PrintStream對象,(PrintStream:打印流。OutputStream的子類)
System.in: 對應的標準輸入設備:鍵盤 //它是InputStream對象
示例:
/*================從鍵盤錄入流,打印到控制檯上================*/
public static void InOutDemo(){
//鍵盤的最常見的寫法
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
/*InputStream ips = System.in; //從鍵盤讀入輸入字節流
InputStreamReader fr = new InputStreamReader(ips); //將字節流轉成字符流
bufr = new BufferedReader(fr); */ //將字符流加強,提升效率
bufr = new BufferedReader(new InputStreamReader(System.in)); //匿名類。InputSteamReader:讀取字節並將其解碼爲字符
bufw = new BufferedWriter(new OutputStreamWriter(System.out)); //OutputStreamWriter:要寫入流中的字符編碼成字節
String line = null;
while((line = bufr.readLine())!=null){
if("over".equals(line)) break;
bufw.write(line.toUpperCase()); //打印
bufw.newLine(); //爲了兼容,使用newLine()寫入換行符
bufw.flush(); //必須要刷新。不然不會顯示
}
if(bufw!=null) {
bufr.close();
bufw.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
2. 整行錄入
1.從鍵盤錄入數據,並存儲到文件中。
2. 我們在鍵盤錄入的是時候,read()方法是一個一個錄入的,能不能整行的錄入呢?這時候我們想到了BufferedReader中ReadLine()方法。
3. 轉換流
爲了讓字節流可以使用字符流中的方法,我們需要轉換流。
1. InputStreamReader:字節流轉向字符流;
a、獲取鍵盤錄入對象。InputStream in=System.in;
b、將字節流對象轉成字符流對象,使用轉換流。
InputStreamReaderisr=new InputStreamReader(in);
c、爲了提高效率,將字符串進行緩衝區技術高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//鍵盤錄入最常見寫法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
2.OutputStreamWriter:字符流通向字節流
示例:
/*================把鍵盤錄入的數據存到一個文件中==============*/
public static void inToFile() {
//鍵盤的最常見的寫法
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
/*InputStream ips = System.in; //從鍵盤讀入輸入字節流
InputStreamReader fr = new InputStreamReader(ips); //將字節流轉成字符流
bufr = new BufferedReader(fr); */ //將字符流加強,提升效率
bufr = new BufferedReader(new InputStreamReader(System.in)); //匿名類。InputSteamReader:讀取字節並將其解碼爲字符
bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt"))); //OutputStreamWriter:要寫入流中的字符編碼成字節
String line = null;
while((line = bufr.readLine())!=null){
if("over".equals(line)) break;
bufw.write(line.toUpperCase()); //打印
bufw.newLine(); //爲了兼容,使用newLine()寫入換行符
bufw.flush(); //必須要刷新。不然不會顯示
}
if(bufw!=null) {
bufr.close();
bufw.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
4. 流操作基本規律
爲了控制格式我將其寫入了Java代碼段中,如下:
示例1:文本 ~ 文本
/*
流操作的基本規律。
一、兩個明確:(明確體系)
1. 明確源和目的
源:輸入流 InputStream Reader
目的:輸出流 OutputStream Writer
2. 操作的數據是否是純文本
是: 字符流
否: 字節流
二、明確體系後要明確具體使用的對象
通過設備區分:內存,硬盤,鍵盤
目的設備:內存,硬盤,控制檯
示例1:將一個文本文件中的數據存儲到另一個文件中: 複製文件
一、明確體系
源:文件-->讀取流-->(InputStream和Reader)
是否是文本:是-->Reader
目的:文件-->寫入流-->(OutputStream Writer)
是否純文本:是-->Writer
二、 明確設備
源:Reader
設備:硬盤上一個文本文件 --> 子類對象爲:FileReader
FileReader fr = new FileReader("Goods.txt");
是否提高效率:是-->加入Reader中的緩衝區:BufferedReader
BufferedReader bufr = new BufferedReader(fr);
目的:Writer
設備:鍵盤上一個文本文件 --> 子類對象:FileWriter
FileWriter fw = new FileWriter("goods1.txt");
是否提高效率:是-->加入Writer的緩衝區:BufferedWriter
BufferedWriter bufw = new BufferedWriter(fw);
示例2:將一個圖片文件數據複製到另一個文件中:複製文件
一、明確體系
源:文件-->讀取流-->(InputStream和Reader)
是否是文本:否-->InputStream
目的:文件-->寫入流-->(OutputStream Writer)
是否純文本:否-->OutputStream
二、 明確設備
源:InputStream
設備:硬盤上一個媒體文件 --> 子類對象爲:FileInputStream
FileInputStream fis = new FileInputStream("Goods.txt");
是否提高效率:是-->加入InputStream中的緩衝區:BufferedInputStream
BufferedInputStream bufi = new BufferedInputStream(fis);
目的:OutputStream
設備:鍵盤上一個媒體文件 --> 子類對象:FileOutputStream
FileOutputStream fos = new FileOutputStream("goods1.txt");
是否提高效率:是-->加入OutputStream的緩衝區:BufferedOutputStream
BufferedOutputStream bufo = new BufferedOutputStream(fw);
示例3:將鍵盤錄入的數據保存到一個文本文件中
一、明確體系
源:鍵盤-->讀取流-->(InputStream和Reader)
是否是文本:是-->Reader
目的:文件-->寫入流-->(OutputStream Writer)
是否純文本:是-->Writer
二、 明確設備
源:InputStream
設備:鍵盤 --> 對用對象爲:System.in --> InputStream
爲了操作方便,轉成字符流Reader --> 使用Reader中的轉換流:InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
是否提高效率:是-->加入Reader中的緩衝區:BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:Writer
設備:鍵盤上一個文本文件 --> 子類對象:FileWriter
FileWriter fw = new FileWriter("goods1.txt");
是否提高效率:是-->加入Writer的緩衝區:BufferedWriter
BufferedWriter bufw = new BufferedWriter(fw);
5.指定編碼表(轉換流可以指定編碼表)
要求:用UTF-8編碼存儲一個文本文件
import java.io.*;
public class IOStreamLaw {
/**
* @param args
*/
public static void main(String[] args) throws IOException {
//鍵盤的最常見寫法
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("goods1.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();
}
}
原文:http://www.cnblogs.com/xll1025/p/6418766.html