2020/4/24-27學習筆記day47/48/49【IO流】

java-day47-48

IO

1.流的概念

流是個抽象的概念,是對輸入輸出設備的抽象,Java程序中,對於數據的輸入/輸出操作都是以"流"的方式進行。設備可以是文件,網絡,內存等

流具有方向性,至於是輸入流還是輸出流則是一個相對的概念,一般以程序爲參考,如果數據的流向是程序至設備,我們成爲輸出流,如果數據的流向是設備至程序稱爲輸入流。

數據以二進制的形式在程序與設備之間流動傳輸,就想水在管道里流動一樣,所以就把這種數據傳輸的方式稱之爲輸入流輸出流
在這裏插入圖片描述

思考:代碼程序中要讀取文件中的內容,需要使用什麼流?代碼程序中要向文件中寫內容,又需要使用什麼流?

2.流的分類

1)按照流的方向分爲輸入流和輸出流
2)按照處理數據的單位不同分爲字節流和字符流
字節流讀取的最小單位是一個字節(1byte=8bit),而字符流一次可以讀取一個字符(1char = 2byte = 16bit)
3)按照功能的不同分爲節點流和處理流
節點流是可以"直接"從一個數據源中讀寫數據的流。
處理流也可以稱爲功能流或者包裝流,它是可以對節點流進行封裝的一種流,封裝後可以增加節點流的功能。
例如:FileInputStream是一個節點流,可以直接從文件讀取數據,而BufferedInputStream可以包裝 FileInputStream,使得其有緩衝數據的功能。

4)除了以上三種分類外,還有其他的一些類型的:對象流、緩衝流、壓縮流、文件流等等,其實這些都是節點流或者處理流的子分類。當然還可以分出來其他的流類型,如果有這樣需要的話。

5)不管流的分類是多麼的豐富和複雜,其根源來自於四個基本的父類
在這裏插入圖片描述

字節輸入流:InputStream
字節輸出流:OutputStream
字符輸入流:Reader
字符輸出流:Writer

注:這四個父類都是抽象類

3.字節流中的常用節點流

注:java中常用的io流都在java.io包中

1)InputStream

在這裏插入圖片描述

//從輸入流中讀取數據的下一個字節
//如果到達流的末尾則返回 -1
public abstract int read();
//把讀到的字節存到字節數組b中,並返回本次讀到了多少個字節
public int read(byte[] b){..}
//把讀到的字節存到字節數組b中,同時指定開始存的位置以及最大字節數,並返回本次讀到了多少個字節
public int read(byte[] b,int off,int len){..}

//返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀取(或跳過)的估計字節數
public int available(){..}

//跳過此輸入流中數據的 n 個字節
public long skip(long n){..}

//關閉此輸入流並釋放與該流關聯的所有系統資源
public void close(){..}

//測試此輸入流是否支持 mark 和 reset 方法
public boolean markSupported(){..}
//在此輸入流中標記當前的位置
public void mark(int readlimit){..}
//將此流重新定位到最後一次對此輸入流調用mark方法時的位置
public void reset(){..}
public int read(byte b[]) throws IOException {
    return read(b, 0, b.length);//0-255
}
public int read(byte b[], int off, int len) throws IOException {
    if (b == null) {
        throw new NullPointerException();
    } else if (off < 0 || len < 0 || len > b.length - off) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return 0;
    }

    int c = read();
    if (c == -1) {
        return -1;
    }
    b[off] = (byte)c;

    int i = 1;
    try {
        for (; i < len ; i++) {
            c = read();
            if (c == -1) {
                break;
            }
            b[off + i] = (byte)c;
        }
    } catch (IOException ee) {
    }
    return i;
}
public long skip(long n) throws IOException {

    long remaining = n;
    int nr;

    if (n <= 0) {
        return 0;
    }

    int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
    byte[] skipBuffer = new byte[size];
    while (remaining > 0) {
        nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
        if (nr < 0) {
            break;
        }
        remaining -= nr;
    }

    return n - remaining;
}
例1:每次讀取單個字節
public class InputStreamTest {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;
		//2、創建流
		in = System.in;//從控制檯讀數據
		//3、使用流
		try {
			int data = in.read();
			System.out.println("data="+data);
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			if(in!=null)
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
	}
}

在這裏插入圖片描述

例2:每次讀取多個字節
public class InputStreamTest2 {
    public static void main(String[] args) {
        //1、聲明流
        InputStream in = null;
        //2、創建流
        in = System.in;//從控制檯讀數據
        //3、使用流
        try {
            //返回讀到的字節數,數據放在數組裏面
            //一次最多讀b.length個字節數,因爲再多一個字節,數組就放不下了
            byte[] b = new byte[5];
            int len = in.read(b);
            System.out.println("本次讀取到"+len+"個字節:"+Arrays.toString(b));
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //4、關閉流
            if(in!=null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }
}

在這裏插入圖片描述

public class InputStreamTest2 {
    public static void main(String[] args) {
        //1、聲明流
        InputStream in = null;
        //2、創建流
        in = System.in;//從控制檯讀數據
        //3、使用流
        try {
            //返回讀到的字節數,數據放在數組裏面
            byte[] b = new byte[5];
            int len = in.read(b);
            System.out.println("本次讀取到"+len+"個字節:"+Arrays.toString(b));
            len = in.read(b);
            System.out.println("本次讀取到"+len+"個字節:"+Arrays.toString(b));
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //4、關閉流
            if(in!=null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }
}

在這裏插入圖片描述

例3:讀取指定位置字節
public class InputStreamTest3 {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;
		//2、創建流
		in = System.in;//從控制檯讀數據
		//3、使用流
		try {
			byte[] b = new byte[5];
            //返回值表示本次共讀到了多少個字節
			//參數1 read方法讀的字節存放到這個數組中
			//參數2指定從數組中哪一個下標開始存數據
			//參數3在數組中最多一次連續存多少個字節
			int len = in.read(b,1,2);
			System.out.println("len="+len+" "+Arrays.toString(b));
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			if(in!=null)
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

在這裏插入圖片描述

例4:通過循環一次讀取全部字節
public class InputStreamTest4 {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;
		//2、創建流
		in = System.in;//從控制檯讀數據
		//3、使用流
		try {
//			int data = -1;
//			while((data=in.read()) != -1) {
//				System.out.println("data="+data);
//			}
			byte[] b = new byte[10];
			int len = -1;
			
			final byte[] BYE = {98, 121, 101, 13, 10};
			
			while( (len=in.read(b)) != -1 ) {
				System.out.println("讀"+len+"個字節: "+Arrays.toString(b));
				
				//前提要求數組b的長度大於等於BYE.length即可
				if(len==5 && Arrays.equals(Arrays.copyOf(b, BYE.length), BYE)) {
					break;
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			if(in!=null)
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
	}
}

在這裏插入圖片描述

例5:available()、markSupported()、mark 和 reset 方法
public class InputStreamTest5 {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;
		//2、創建流
		in = System.in;//從控制檯讀數據
		
		//System.out.println(in.getClass());
		//實際類型  java.io.BufferedInputStream
		
		//3、使用流
		try {
			//返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀取(或跳過)的估計字節數
			System.out.println("in.available():"+in.available());
			//可以在讀數據之前,先跳過指定的字節數
			//in.available()的方法值,就是這個方法可以跳過的最大字節數
			//System.out.println(in.skip(10));
			
			//測試此輸入流是否支持 mark 和 reset 方法
			System.out.println("in.markSupported():"+in.markSupported());
			
			int data = -1;
			
			//hello 
			//104 101 108 108 111
			while((data=in.read())!=-1) {
				if(data==104) {
					//在此輸入流中標記當前的位置
					in.mark(5);
				}
				else if(data==111) {
					//將此流重新定位到最後一次對此輸入流調用mark方法時的位置
					in.reset();
				}
				System.out.println("data="+data);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			if(in!=null)
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
	}
}

在這裏插入圖片描述

2)OutputStream

在這裏插入圖片描述

//將指定的字節寫入此輸出流
public abstract void write(int b);
//將字節數組b中的所有字節寫入此輸出流
public void write(byte[] b){..}
//將字節數組b中的字節寫入此輸出流,指定開始位置及最大字節數
public void write(byte[] b,int off,int len){..}

//刷新此輸出流並強制寫出所有緩衝的輸出字節
public void flush(){..}

//關閉此輸出流並釋放與此流有關的所有系統資源
public void close(){..}
例6:結合InputStream和OutputStream
public class OutputStreamTest2 {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;
		OutputStream out = null;

		//2、創建流
		in = System.in;
		out = System.out;
		
		//3、使用流
		try {
			
			byte[] b = new byte[5];
			int len = -1;
			while((len=in.read(b))!=-1) {
				out.write(b,0,len);//讀出幾個字節寫幾個字節
				out.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
				try {
					if(out!=null)
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				try {
					if(in!=null)
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
	}
}

在這裏插入圖片描述

3)InputStream的子類和OutputStream的子類

幾乎都是成對出現的,一個負責讀數據的工作,一個負責寫數據的工作

4)System.out和System.in

System類的部分源碼:

public final class System{
    //標準輸入流
    public final static InputStream in = null;
    //標準輸出流。
    public final static PrintStream out = null;
    //標準錯誤輸出流
    public final static PrintStream err = null;

    public static void setIn(InputStream in){..}
    public static void setOut(PrintStream out){..}
    public static void setErr(PrintStream err){..}
}

標準輸入流會默認從控制檯讀取數據
標準輸出流會默認把數據輸出到控制檯

System.out.println(System.in.getClass());
System.out.println(System.out.getClass());

輸出結果爲:

class java.io.BufferedInputStream
class java.io.PrintStream
5)ByteArrayInputStream和ByteArrayOutputStream

ByteArrayInputStream可以從數組中讀取字節
ByteArrayOutputStream可以把字節寫到對象中的緩衝區裏面,其實就是一個字節數組

public class ByteArrayInputStreamTest {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;


		//2、創建流
		//把字符串變成字符數組
		byte[] buf = "hello world".getBytes();
		in = new ByteArrayInputStream(buf);
		
		//3、使用流
		try {
			System.out.println("in.available():"+in.available());
			//in.skip(in.available());全部被跳過
			System.out.println("in.markSupported():"+in.markSupported());
			int data = -1;
			while((data=in.read())!=-1) {
				if(data=='e') {
					in.mark(1);//標記 參數沒有用
				}
				else if(data == ' '){
					in.reset();
				}
				//輸出字節
				System.out.write(data);
				//將緩衝區數據刷新到控制檯
				System.out.flush();
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			try {
				if(in!=null)
				in.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
}

在這裏插入圖片描述

public class ByteArrayOutputStreamTest {
	public static void main(String[] args) {
		//1、聲明流
		OutputStream out = null;


		//2、創建流
		//把字符串變成字符數組
		out = new ByteArrayOutputStream();
		
		//3、使用流
		try {
			//把數據寫到ByteArrayoutputStream對象中的buf屬性中,buf是字節數組
			byte[] b = "abc".getBytes();
			out.write(b);
			out.flush();
			byte[] result = ((ByteArrayOutputStream)out).toByteArray();
			System.out.println(Arrays.toString(result));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			try {
				if(out!=null)
				out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
}

在這裏插入圖片描述

6)FileInputStream和FileOutputStream

FileInputStream可以讀取文件中的字節
FileOutputStream可以向文件中寫進去字節

public class FileInputStreamTest {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;


		try {
			//2、創建流
			String fileName = "src/com/zzb/day47/test.txt";
			in = new FileInputStream(fileName);
			
			
			//3、使用流
			byte [] b = new byte[10];
			int len = -1;
			long first = System.currentTimeMillis();
			while((len=in.read(b)) != -1) {
				System.out.write(b,0,len);
			}
			System.out.flush();
			long end = System.currentTimeMillis();
			System.out.println("耗時:"+(end-first)+"毫秒");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			try {
				if(in!=null)
				in.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
}

在這裏插入圖片描述

public class FileOutputStreamTest {
	public static void main(String[] args) {
		//1、聲明流
		InputStream in = null;
		OutputStream out = null;
		
		

		try {
			//2、創建流
			String readFileName = "src/com/zzb/day47/test1.txt";
			in = new FileInputStream(readFileName);
			
			String writeFileName = "src/com/zzb/day47/test2.txt";
			//構造器第二個參數,false表示內容覆蓋,true表示內容追加
			//如果使用的一參構造器,那麼默認就是覆蓋
			out = new FileOutputStream(writeFileName,true);
			
			//3、使用流
			byte [] b = new byte[10];
			int len = -1;
			long first = System.currentTimeMillis();
			while((len=in.read(b)) != -1) {
				out.write(b,0,len);
			}
			out.flush();
			
			long end = System.currentTimeMillis();
			System.out.println("耗時:"+(end-first)+"毫秒");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//4、關閉流
			try {
				if(in!=null)
				in.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			try {
				if(out!=null)
				out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
}

在這裏插入圖片描述

7)PipedInputStream和PipedOutputStream

在這裏插入圖片描述

PipedInputStream管道字節輸入流
PipedOutputStream管道字節輸出流

注:使用時需要把倆個管道進行對接

public class PipedStreamTest {
	
	public static void main(String[] args) {
		
		PipedInputStream in;
		PipedOutputStream out;
		
		try {
			in = new PipedInputStream();
			//讓管道進行對接
			out = new PipedOutputStream(in);
			
			
			//把in和out分別交給倆個線程t1 t2,讓線程操作管道流進行數據的傳輸
			
			Thread t1 = new MyThread1(out);
			Thread t2 = new MyThread2(in);
			
			t1.start();
			t2.start();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	//複雜往管道中寫數據
	private static class MyThread1 extends Thread{
		
		private PipedOutputStream out;
		
		public MyThread1(PipedOutputStream out) {
			this.out = out;
		}
		
		@Override
		public void run() {
			
			int data = -1;
			try {
				for(;;) {
					data = (int)(Math.random()*26)+97;
					out.write(data);
					out.flush();
					Thread.sleep(1000);
					if(data == 'x') {
						break;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					if(out!=null)out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
	//負責從管道中讀寫數據
	private static class MyThread2 extends Thread{
		
		private PipedInputStream in;
		
		public MyThread2(PipedInputStream in) {
			this.in = in;
		}
		
		@Override
		public void run() {
			
			int data = -1;
			try {
				while((data=in.read()) != -1) {
					System.out.write(data);
					System.out.flush();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}finally {
				try {
					if(in!=null)in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
	
}

在這裏插入圖片描述

8)ObjectInputStream和ObjectOutputStream

在序列化中要使用的對象輸入流和對象輸出流,之後再來使用測試

9)java.io.File類

File類型對象可以表示一個文件也可以表示一個目錄.

package com.zzb.day48;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;

public class FileTest {
	
	public static void main(String[] args) {
		
		FileTest t = new FileTest();
		
		t.test1();
		
	}
	
	
	public void test1() {
		
		File file = null;
		
//		String pathName = "src/com/zzb/day48";
		String pathName = "src/com/zzb/day48/test.txt";
		file = new File(pathName);
		
		System.out.println("是否存在:\t"+file.exists());//該file表示的文件或者文件夾存不存在
		System.out.println("是否是文件夾:\t"+file.isDirectory());//判斷file表示的是不是文件夾
		System.out.println("是否是文件:\t"+file.isFile());//判斷file表示的是不是文件
		
		System.out.println("是否可讀:\t"+file.canRead());
		System.out.println("是否可寫:\t"+file.canWrite());
		System.out.println("是否可執行:\t"+file.canExecute());
		
		System.out.println("文件名字:\t"+file.getName());
		System.out.println("文件路徑:\t"+file.getPath());
		System.out.println("文件絕對路徑:\t"+file.getAbsolutePath());
		
		System.out.println("----------------------------------------");
		
//		String parentName = file.getParent();
//		System.out.println(parentName);
		//獲取file的父目錄
		File parentFile = file.getParentFile();
		System.out.println("file的父目錄爲:\t"+parentFile.getPath());
		
		//返回這個父目錄中所有的文件或子目錄
		File[] listFiles = parentFile.listFiles();
		for(File f:listFiles) {
			System.out.println(f.getName());
		}
		
		System.out.println("-----------------------------------------");
		
		
		listFiles = parentFile.listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return file.isFile() && file.canRead();
			}
		});
		
		for(File f:listFiles) {
			System.out.println(f.getName());
		}
		
		
		
		
	}
	
	public void test2() {
		
		File file = null;
		String pathName = "src/com/zzb/day48/test1.txt";
		
		try {
			file = new File(pathName);
			
			if(file.exists() == false) {
				System.out.println("創建文件是否成功:\t"+file.createNewFile());
			}
			
			if(file.exists() == true && file.length()==0) {
				file.delete();
//				file.deleteOnExit();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	public void test3() {
		
		File file = null;
		String pathName = "src/com/zzb/day48/";
		
		try {
//			for(int i=1;i<=10;i++) {
//				pathName = "src/com/briup/day48/test"+i+".txt";
//				file = new File(pathName);
//				if(file.exists() == false) {
//					file.createNewFile();
//				}
//			}
			
			file = new File(pathName);
			if(file.exists() && file.isDirectory()) {
				
				File[] list = file.listFiles(new FileFilter() {
					@Override
					public boolean accept(File f) {
						return f.isFile() && f.getName().endsWith("txt") && f.length()==0;
					}
				});
				
				for(File f:list) {
					f.delete();
				}
				
			}
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	public void test4() {
		File file = null;
		String pathName = "src/com/zzb/day48/test";
		
		try {
			
			file = new File(pathName);
			if(file.exists() == false) {
				file.mkdir();
			}
			if(file.exists() == true) {
				file.delete();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

4.字節流中的常用處理流

也可以稱爲功能流或者包裝流,因爲它是對節點流進行包裝的一種流,包裝後可以增加節點流的功能。但是處理流本身並不能直接讀寫數據

1)BufferedInputStream和BufferedOutputStream

可以給字節流中的節點流提供代碼緩衝區的輸入/輸出流

package com.zzb.day48;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class BufferedInputStreamTest {
	
	@SuppressWarnings("unused")
	public static void main(String[] args) {
		
		InputStream in = null;
		
		try {
			String filePath = "src/com/zzb/day48/io.txt";
			in = new FileInputStream(filePath );
	      //in = new BufferedInputStream(new FileInputStream(filePath));
			
			long start = System.currentTimeMillis();
			
          //int data = -1;
			byte[] b = new byte[1024];
			int len = -1;
			while((len=in.read(b))!=-1) {
				//
			}
			
			long end = System.currentTimeMillis();
			
			System.out.println("共耗時"+(end-start)+"毫秒");
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(in!=null)in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}	
	}	
}
package com.zzb.day48;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class BufferedOutputStreamTest {
	
	public static void main(String[] args) {
		
		OutputStream out = null;
		
		try {
			String filePath = "src/com/zzb/day48/test.txt";
			out = new BufferedOutputStream(new FileOutputStream(filePath));
//			out = new FileOutputStream(filePath);
			
			byte[] b = "hello world\n".getBytes();
			
			long start = System.currentTimeMillis();
			
			for(int i=0;i<10000;i++) {
				out.write(b );
			}
			out.flush();
			
			long end = System.currentTimeMillis();
			
			System.out.println("共耗時"+(end-start)+"毫秒");
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(out!=null)out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
}
2)DataInputStream和DataOutputStream

可以給字節流中的節點流提供輸入/輸出java中不同類型的數據

public final void writeInt(int v) throws IOException {
    out.write((v >>> 24) & 0xFF);
    out.write((v >>> 16) & 0xFF);
    out.write((v >>>  8) & 0xFF);
    out.write((v >>>  0) & 0xFF);
    incCount(4);
}
public final void writeShort(int v) throws IOException {
    out.write((v >>> 8) & 0xFF);
    out.write((v >>> 0) & 0xFF);
    incCount(2);
}
public final void writeLong(long v) throws IOException {
    writeBuffer[0] = (byte)(v >>> 56);
    writeBuffer[1] = (byte)(v >>> 48);
    writeBuffer[2] = (byte)(v >>> 40);
    writeBuffer[3] = (byte)(v >>> 32);
    writeBuffer[4] = (byte)(v >>> 24);
    writeBuffer[5] = (byte)(v >>> 16);
    writeBuffer[6] = (byte)(v >>>  8);
    writeBuffer[7] = (byte)(v >>>  0);
    out.write(writeBuffer, 0, 8);
    incCount(8);
}
public final void writeBoolean(boolean v) throws IOException {
    out.write(v ? 1 : 0);
    incCount(1);
}
public final void writeFloat(float v) throws IOException {
    writeInt(Float.floatToIntBits(v));
}
public static int floatToIntBits(float value) {
    int result = floatToRawIntBits(value);
    // Check for NaN based on values of bit fields, maximum
    // exponent and nonzero significand.
    if ( ((result & FloatConsts.EXP_BIT_MASK) ==
          FloatConsts.EXP_BIT_MASK) &&
        (result & FloatConsts.SIGNIF_BIT_MASK) != 0)
        result = 0x7fc00000;
    return result;
}
public final void writeDouble(double v) throws IOException {
    writeLong(Double.doubleToLongBits(v));
}
public static long doubleToLongBits(double value) {
    long result = doubleToRawLongBits(value);
    // Check for NaN based on values of bit fields, maximum
    // exponent and nonzero significand.
    if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
          DoubleConsts.EXP_BIT_MASK) &&
        (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
        result = 0x7ff8000000000000L;
    return result;
}
public class DataOutputStreamTest {
	public static void main(String[] args) {
		OutputStream out = null;
		
		try {
			String filePath="src/com/zzb/day48/test.txt";
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			out = new DataOutputStream(bos);
			((DataOutputStream)out).writeLong(1000L);
			byte[] result= bos.toByteArray();
			
			out.flush();
			System.out.println(Arrays.toString(result));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(out!=null)
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

在這裏插入圖片描述

package com.zzb.day48;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;

@SuppressWarnings("unused")
public class DataOutputStreamTest {
	public static void main(String[] args) {
		OutputStream out = null;
		
		try {
			String filePath="src/com/zzb/day48/test.txt";
//			out = new DataOutputStream(new FileOutputStream(filePath));

			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			out = new DataOutputStream(bos);
//			((DataOutputStream)out).writeLong(1000L);
			((DataOutputStream)out).writeDouble(123.5D);
			byte[] result= bos.toByteArray();
			
			out.flush();
			System.out.println(Arrays.toString(result));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(out!=null)
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

在這裏插入圖片描述

解釋上面兩個例子

public class Test {
	public static void main(String[] args) {
		String str = Long.toBinaryString(1000L);
		System.out.println(str);
		//00000000 00000000 00000000 00000000
		//00000000 00000000 00000011 11101000
		//1110100 -> 00010111 + 1 -> 00011000   -24
		//{0,0,0,0,0,0,3,-24}
		
		long a = Double.doubleToLongBits(123.5D);
		//4638390956842811392
		System.out.println(a);
		//01000000 01011110 1110000 00000000
		//00000000 00000000 0000000 00000000
		//{64,94,-32,0,0,0,0,0}
		System.out.println(Long.toBinaryString(a));
	}
}

利用兩個包裝流進行讀寫

public class DataOutputStreamTest {
	public static void main(String[] args) {
		OutputStream out = null;
		
		try {
			String filePath="src/com/zzb/day48/test.txt";
			out = new DataOutputStream(new FileOutputStream(filePath));
			((DataOutputStream)out).writeInt(50529025);
			((DataOutputStream)out).writeInt(1);
			((DataOutputStream)out).writeLong(1000L);
			((DataOutputStream)out).writeUTF("HELLO");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(out!=null)
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

在這裏插入圖片描述

public class DataInputStreamTest {
	public static void main(String[] args) {
		InputStream in = null;
		try {
			String filePath ="src/com/zzb/day48/test.txt";
			in = new DataInputStream(new FileInputStream(filePath));
			System.out.println(((DataInputStream)in).readInt());
			System.out.println(((DataInputStream)in).readInt());
			System.out.println(((DataInputStream)in).readLong());
			System.out.println(((DataInputStream)in).readUTF());	
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(in!=null)
					in.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
		}	
	}
}

在這裏插入圖片描述

3)PrintStream

PrintStream爲其他輸出流添加了功能,使它們能夠方便地打印各種數據值表示形式
注意,這個包裝類中的方法可以接受各種各種的類型的參數(重載),但是內部會把這些數據再變成相應的字符串,然後在進行輸出。

public class PrintStreamTest {
	public static void main(String[] args) {
		PrintStream out = null;
		ByteArrayOutputStream bos = null;
		try {
			bos = new ByteArrayOutputStream();
			out = new PrintStream(bos);
			out.println(1000L);
			//1000 -> 字符串 1 0 0 0 回車 換行
			out.flush();
			
			byte[] buf =bos.toByteArray();
			System.out.println(Arrays.toString(buf));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(bos!=null)
					bos.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
		}	
	}
}

在這裏插入圖片描述

5.字符流

1)Reader

在這裏插入圖片描述

public int read(){..}
public int read(char[] cbuf){..}
public abstract int read(char[] cbuf, int off,int len){..}
//指定緩衝區
//@since 1.5
public int read(CharBuffer target){..}

abstract public void close();
public long skip(long n){..}

public boolean markSupported(){..}
public void mark(int readAheadLimit){..}
public void reset(){..}

//Tells whether this stream is ready to be read
public boolean ready(){..}
2)Writer

在這裏插入圖片描述

public void write(int c){..}
public void write(char cbuf[]){..}
abstract public void write(char cbuf[], int off, int len);
public void write(String str){..}
public void write(String str, int off, int len){..}

abstract public void flush();
abstract public void close();

//@since 1.5
//和out.write(c)的效果一樣
public Writer append(char c){..}
public Writer append(CharSequence csq){..}
public Writer append(CharSequence csq, int start, int end){..}
3)CharArrayReader和CharArrayWriter

CharArrayReader可以讀取字符數組中的內容

public class CharArrayReaderTest {
	public static void main(String[] args) {
		Reader in = null;
		try {
			char[] buf = "中國 hello".toCharArray();
			in = new CharArrayReader(buf);
			
			/*
			int data = -1;
			while((data=in.read())!=-1) {				
				//System.out.write(data);
				System.out.flush();
			}*/
			int len = -1;
			char[] cbuf = new char[5];
			while((len=in.read(cbuf))!=-1) {
				System.out.println(len+":"+Arrays.toString(cbuf));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(in!=null)
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

在這裏插入圖片描述

CharArrayWriter可以向字符數組中寫內容

public class CharArrayWriterTest {
	public static void main(String[] args) {
		Writer out = null;
		try {
			out = new CharArrayWriter();
			out.write("鄒澤斌");
			out.flush();
			char [] buf =((CharArrayWriter)out).toCharArray();
			System.out.println(Arrays.toString(buf));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				try {
					if(out!=null)
					out.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
		}
	}
}

在這裏插入圖片描述

4)FileReader和FileWriter

FileReader讀取文件內容的便捷類,InputStreamReader的子類

public class FileReaderTest {
	
	public static void main(String[] args) {
		
		
		Reader in = null;
		
		try {
			String fileName = "src/com/zzb/day49/io.txt";
			in = new FileReader(fileName );
			
			char[] cbuf = new char[1024];
			int len = -1;
			
			while((len=in.read(cbuf)) != -1) {
				String str = new String(cbuf,0,len);
				System.out.print(str);
			}
			System.out.flush();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(in!=null)in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		
	}
	
}

FileWriter寫入文件內容的便捷類,OutputStreamWriter的子類

public class FileWriterTest {
	
	public static void main(String[] args) {
		
		
		Reader in  = null;
		Writer out = null;
		
		try {
			String readFileName = "src/com/zzb/day49/io.txt";
			in = new FileReader(readFileName);
			
			String writeFileName = "src/com/zzb/day49/test.txt";
			out = new FileWriter(writeFileName);
			
			char[] cbuf = new char[1024];
			int len = -1;
			
			while((len=in.read(cbuf)) != -1) {
				out.write(cbuf, 0, len);
			}
			out.flush();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(in!=null)in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(out!=null)out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		
	}
	
}
5)PipedReader和PipedReader

PipedReader管道字符輸入流
PipedReader管道字符輸出流

在這裏插入圖片描述

public class PipedReaderTest {
	
	public static void main(String[] args) {
		
		PipedReader in  = null;
		PipedWriter out = null;
		
		try {
			in  = new PipedReader();
			out = new PipedWriter(in);
			
			Thread t1 = new MyThread1(in);
			Thread t2 = new MyThread2(out);
			
			t1.start();
			t2.start();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	
	private static class MyThread1 extends Thread {
		private PipedReader in;
		public MyThread1(PipedReader in) {
			this.in = in;
		}
		
		@Override
		public void run() {
			
			int data = -1;
			
			try {
				while((data=in.read())!=-1) {
					System.out.write(data);
					System.out.flush();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}finally {
				try {
					if(in!=null)in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
	
	private static class MyThread2 extends Thread {
		private PipedWriter out;
		public MyThread2(PipedWriter out) {
			this.out = out;
		}
		
		@Override
		public void run() {
			try {
				for(int i=0;i<256;i++) {
					out.write(i);
					out.flush();
					if(i%20==0) {
						System.out.print("\n---------分割--------\n");
					}
					Thread.sleep(100);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					if(out!=null)out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	
	
}

public class PipedReaderTest2 {
	
	public static void main(String[] args) {
		
		PipedReader in  = null;
		PipedWriter out = null;
		
		try {
			in  = new PipedReader();
			out = new PipedWriter(in);
			
			Thread t1 = new MyThread1(in);
			Thread t2 = new MyThread2(out);
			
			t1.start();
			t2.start();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	
	private static class MyThread1 extends Thread {
		private PipedReader in;
		public MyThread1(PipedReader in) {
			this.in = in;
		}
		
		@Override
		public void run() {
			Writer out = null;
			
			try {
				String fileName = "src/com/zzb/day49/a.txt";
				out = new FileWriter(fileName);
				
				char[] cbuf = new char[128];
				int len = -1;
				while((len=in.read(cbuf)) != -1) {
					out.write(cbuf, 0, len);
					out.flush();
				}
				
			} catch (IOException e) {
				e.printStackTrace();
			}finally {
				try {
					if(in!=null)in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if(out!=null)out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
	
	private static class MyThread2 extends Thread {
		private PipedWriter out;
		public MyThread2(PipedWriter out) {
			this.out = out;
		}
		
		@Override
		public void run() {
			Reader in = null;
			try {
				
				in = new InputStreamReader(System.in);
				
				char[] cbuf = new char[128];
				int len = -1;
				
				while((len=in.read(cbuf)) != -1) {
					out.write(cbuf, 0, len);
					out.flush();
				}
				
				
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					if(in!=null)in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if(out!=null)out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}	
}

6)BufferedReader和BufferedWriter

這個倆個流屬於處理流,它們本身並不能讀取數據,它們的作用是包裝在其他節點流上面,爲其提供額外的功能

public class BufferedReaderTest2 {
	
	public static void main(String[] args) {
		
		BufferedReader in = null;
		
		try {
			
			String fileName = "src/com/zzb/day49/stu.txt";
			in = new BufferedReader(new FileReader(fileName ));
			
			String line = null;
			
			List<Student> list = new ArrayList<>();
			
			while((line=in.readLine()) != null) {
				Student stu = stringToStudent(line);
				if(stu==null) {
					System.out.println("當前數據有問題,直接進入下次操作:"+line);
					continue;
				}
				list.add(stu);
			}
			
			System.out.println("list.size() = "+list.size());
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(in!=null)in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		
	}

	private static Student stringToStudent(String line) {
		//1:tom1:21
		
		String[] arr = line.split(":");
		if(arr.length != 3) {
			return null;
		}
		
		long 	id 	= Long.valueOf(arr[0]);
		String name = arr[1];
		int 	age = Integer.valueOf(arr[2]);
		
		return new Student(id,name,age);
	}
	
}

public class BufferedWriterTest {
	
	public static void main(String[] args) {
		
		//window中默認是\r\n
		//linux中默認是\n
//		String str = System.getProperty("line.separator");
//		System.out.println(Arrays.toString(str.getBytes()));
		
		BufferedWriter out = null;
		
		try {
			String fileName = "src/com/zzb/day49/a.txt";
			out = new BufferedWriter(new FileWriter(fileName ));
			
			
			out.write("hello");
			out.newLine();
			out.write("world");
			out.newLine();
			
			
			out.flush();
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(out!=null)out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
}
7)PrintWriter

一般會把BufferedReader和PrintWriter配合在一起使用,因爲BufferedReader可以一次讀一行字符串,而PrintWriter可以一次寫一行字符串(自動換行)。

public class PrintWriterTest {
	
	public static void main(String[] args) {
		
		PrintWriter out = null;
		
		try {
//			String fileName = "src/com/zzb/day49/a.txt";
//			out = new PrintWriter(new File(fileName ));
//			out = new PrintWriter(System.out);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			out = new PrintWriter(bos);
			
			out.println("hello1");
			out.println("hello2");
			out.println("hello3");
			
			out.flush();
			
			byte[] buf = bos.toByteArray();
			System.out.println(Arrays.toString(buf));
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(out!=null)out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		
	}
	
}
public class PrintWriterTest2 {

    public static void main(String[] args) {

        PrintWriter out = null;

        try {

            String fileName = "src/com/zzb/day49/stu.txt";
            out = new PrintWriter(new File(fileName));

            List<Student> list = getStudents();
            //new Student(1L,"tom1",21) --> 1:tom1:21

            for(Student stu:list) {
                out.println(stu.toString());
            }
            out.flush();

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(out!=null)out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    private static List<Student> getStudents(){

        List<Student> list = new ArrayList<>();

        list.add(new Student(1L,"tom1",21));
        list.add(new Student(2L,"tom2",22));
        list.add(new Student(3L,"tom3",23));
        list.add(new Student(4L,"tom4",24));
        list.add(new Student(5L,"tom5",25));

        return list;
    }
}
public class Student implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	private long id;
	private String name;
	private transient int age;
	
	public Student() {
	}

	public Student(long id, String name, int age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
	
}

6.轉換流

InputStreamReader和OutputStreamWriter是一對名字中既有Stream,又有Reader或Writer的流,因爲它們是轉換流,負責把一個字節流轉換爲字符流。所以它們是字節流和字符串之間的橋樑.
注:在把字節流轉換爲字符流的過程中,還可以指定字符編碼,避免亂碼的出現。

public class InputStreamReaderTest {
	
	public static void main(String[] args) {
		
		
		BufferedReader in = null;
		
		try {
			String fileName = "src/com/zzb/day49/a.txt";
//			in = new InputStreamReader(new FileInputStream(fileName ));
			
			String charsetName = "UTF-8";
//			String charsetName = "GBK";
			in = new BufferedReader(
					new InputStreamReader(new FileInputStream(fileName),charsetName));
			
			String line = null;
			while((line=in.readLine()) != null) {
				System.out.println(line);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(in!=null)in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}	
	}	
}
public class OutputStreamWriterTest {
	
	public static void main(String[] args) {
		
		PrintWriter out = null;
		
		try {
			String fileName = "src/com/zzb/day49/a.txt";
			String charsetName = "UTF-8";
//			String charsetName = "GBK";
			out = new PrintWriter(
					new OutputStreamWriter(new FileOutputStream(fileName),charsetName));
			
//			out = new PrintWriter(fileName);
//			out = new PrintWriter(new FileOutputStream(fileName));
			
			out.println("你好,hello");
			out.flush();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(out!=null)out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
}

7.對象流

1)序列化和反序列化

Java中的序列化是指把Java對象轉換爲字節序列的過程
對象—序列化—>01010101
Java中的反序列化是指把字節序列恢復爲Java對象的過程
01010101—反序列化—>對象

思考:爲什麼需要序列化和反序列化?

2)如何實現序列化和反序列化

使用對象流即可實現對象的序列化和反序列化
ObjectOutputStream類中的方法可以完成對象的序列化:
public final void writeObject(Object obj){…}

public class ObjectOutputStreamTest {
	
	public static void main(String[] args) {
		
		ObjectOutputStream out = null;
		
		try {
			String fileName = "src/com/zzb/day49/obj.txt";
			out = new ObjectOutputStream(new FileOutputStream(fileName ));
			
			Student stu = new Student(1L,"tom1",21);
			
			//對象的序列化
			//對象--->字節
			out.writeObject(stu);
			
			out.flush();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(out!=null) out.close();
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		
	}
	
}
	
	public static void main(String[] args) {
		
		ObjectOutputStream out = null;
		
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			out = new ObjectOutputStream(bos);
			
			List<Student> list = new ArrayList<>();
			for(int i=1;i<=20;i++) {
				list.add(new Student(i,"tom"+i,20+i));
			}
			
			out.writeObject(list);
			out.flush();
			
			byte[] buf = bos.toByteArray();
			System.out.println(buf.length);
			System.out.println(Arrays.toString(buf));
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(out!=null) out.close();
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		
	}
	
}

ObjectInputStream類中的方法可以完成對象的反序列化:
public final Object readObject(){…}

public class ObjectInputStreamTest {
	
	public static void main(String[] args) {
		
		ObjectInputStream in = null;
		
		try {
			String fileName = "src/com/zzb/day49/obj.txt";
			in = new ObjectInputStream(new FileInputStream(fileName ));
			
			//對象的反序列化
			//字節 --->對象
			Object obj = in.readObject();
			
			System.out.println(obj instanceof Student);
			System.out.println(obj);
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(in!=null) in.close();
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		
	}
	
}

注:這倆個對象流都屬於字節流

3)序列化的要求

只有實現了java.io.Serializable接口的類的對象纔可以被序列化,否則序列化時會報錯

思考:測試序列化版本號的作用是什麼?

4)transient關鍵字

在對象序列化的時候,被transient修飾的屬性的值,在序列化過程中是會被忽略掉的。

8.隨機訪問流

java.io.RandomAccessFile類
public class RandomAccessFile extends Object{…}
這是個特殊的流,它不屬於之前那些流的體系。

這個流的既可以用來讀文件,也可以用來給文件中寫內容,並且該類中的方法可以用來定位文件中的位置:
public native void seek(long pos);

構造器中需要設置該流的操作模式:

//對文件只讀
RandomAccessFile r = new RandomAccessFile(filePath,"r");
//對文件即可讀又可寫
//但是一旦確定了讀或者寫,那麼就不能在變
RandomAccessFile rw = new RandomAccessFile(filePath,"rw");
public class RandomAccessFileTest {

    public static void main(String[] args) {

        //針對文件的 隨機訪問流
        //和之前的流不同之處在於,這種流不僅可以在讀的時候進行隨機定位,再寫的時候也可以進行隨機定位。
        RandomAccessFile in  = null;
        RandomAccessFile out = null;


        try {

            File file = new File("src/com/zzb/day49/test.txt");

            in  = new RandomAccessFile(file, "r");
            out = new RandomAccessFile("src/com/zzb/day49/testCopy.txt", "rw"); 

            byte[] buf = new byte[128];
            int len = -1;

            long fileLength = file.length();
            in.seek(fileLength/2);
            out.seek(fileLength/2);
            while((len=in.read(buf))!=-1) {
                out.write(buf, 0, len);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {

            try {
                if(in!=null)in.close();
            } catch (IOException e) {
                e.printStackTrace();
            } 

            try {
                if(out!=null)out.close();
            } catch (IOException e) {
                e.printStackTrace();
            } 

        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章