一、IO流概述
1.原理
2.流的分類


3.流的體系,藍底框為重點掌握的

二、IO流操作
1.節點流-字符流
(1).FileReader讀入資料的基本操作
點擊查看代碼
package com.Tang.io;
import org.junit.Test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class IOTest {
@Test
public void test() {
FileReader fr = null;
//為了保證流資源一定可以執行關閉操作,需要使用try-catch-finally
//讀入的檔案一定要存在,否則就會報FileNotFoundException,
try {
//將Hello工程下的hello.txt檔案內容讀入程式中,并輸出到控制臺
//1.實體化File類物件,指明要操作的檔案
File file = new File("hello.txt");
//2.提供具體的流
fr = new FileReader(file);
//3.資料的讀入
//read():回傳讀入的一個字符,如果達到檔案末尾,回傳-1;否則回傳字符的Ascall值
int data = https://www.cnblogs.com/twq46/p/fr.read();
while(data != -1){
System.out.print((char)data);//讀取檔案第一個字符
data = fr.read();//讀取檔案下一個字符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的關閉操作
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


①.FileReader對read()操作升級:使用read的多載方法
代碼中for回圈處如果寫為i < cubf.length會出現一下問題 點擊查看代碼
//對read()操作升級:使用read的多載方法
@Test
public void test1(){
FileReader fr = null;
try {
//1.File類的實體化
File file = new File("hello.txt");
//2.FileReader流的實體化
fr = new FileReader(file);
//3.讀入的操作
//read(char[] cbuf):回傳每次讀入cbuf陣列中的字符的個數,當讀到檔案末尾時回傳-1
char[] cbuf = new char[5];//相當于一個容量池,每次能從檔案能讀出的最大字符數
int len;
while((len = fr.read(cbuf) )!= -1){
//方式一:
//錯誤寫法
// for (int i = 0; i <cbuf.length ; i++) {
// System.out.print(cbuf[i]);
// }
//正確寫法:每次讀到幾個字符就輸出幾個
// for (int i = 0; i <len; i++) {
// System.out.print(cbuf[i]);
// }
//方式二:
// 將陣列轉化為字符,因為每一次讀到的字符都是在上一次陣列上的覆寫
//因此每次只需取出從陣列開始位置到所能讀到的字符的即可結束
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// fr.read(cbuf);
}

(2)FileWriter寫出資料的操作
點擊查看代碼
/*
1.輸出操作,對應的File可以不存在,并不會報例外
2.
File對應的硬碟中的檔案如果不存在:在輸出的程序中,會自動創建此檔案
File對應的硬碟中的檔案如果存在:
如果流使用的構造器是FileWriter(file,false) / FileWriter(false):對原有檔案的覆寫
如果流使用的構造器是FileWriter(file,true) /:不會對原有檔案覆寫,而是在原有檔案基礎上追加內容
*/
@Test
public void test2() {
FileWriter fw = null;
try {
//1.提供File類的物件,指明寫出到的檔案
File file = new File("hello1.txt");
//2.提供FileWriter的物件,用于資料的寫出
fw = new FileWriter(file);
//3.寫出的操作
fw.write("I have a dream\n");
fw.write("you need to hava a dream");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流資源的關閉
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

(3).使用FileReader和FileWriter實作文本檔案的復制
①一開始就按下方圖片的代碼去寫,然后選中除關閉流的以外的代碼按快捷鍵ctrl + alt + t生成 try - catch - finally然后將關閉流的代碼放入finally中并單獨生成 try - catch 點擊查看代碼
@Test
public void test3(){
FileReader fr = null;
FileWriter fw = null;
try {
//1.創建File類的物件,指明讀入和寫出的檔案
File file = new File("hello.txt");
File file1 = new File("hello2.txt");
//2.創建輸入流和輸出流的物件
fr = new FileReader(file);
fw = new FileWriter(file1);
//3.資料的讀入和寫出操作
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){//從hello.txt文本中讀入到cbuf陣列len個字符
//每次將讀入到的len個字符寫出到hello2.txt中
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.關閉流資源
try {
if(fw !=null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

注意:字符流不能處理圖片檔案的測驗
2.節點流-位元組流
(1)FileInputStream的使用
①位元組流處理文本檔案
點擊查看代碼
/*
結論:
1.對于文本檔案(.txt , .java , .c , .cpp)使用字符流處理
2.對于非文本檔案(.jpg, .mp3, .mp4, .doc, .ppt ......)使用位元組流處理
*/
@Test
public void test4(){
//使用位元組流FileInputStream處理文本檔案,可能出現亂碼
FileInputStream fis = null;
try {
//1.造檔案
File file = new File("hello.txt");
//2.造流
fis = new FileInputStream(file);
//3.讀資料
byte[] bytes = new byte[5];
int len;//記錄每次讀取的位元組的個數
while((len=fis.read(bytes)) != -1){
String str = new String(bytes,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {//4.關閉資料
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
②位元組流處理非文本檔案
點擊查看代碼
//實作對圖片的復制
@Test
public void test5() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File file = new File("QQ20210927-0.jpg");
File file1 = new File("QQ20210927-1.jpg");
fis = new FileInputStream(file);
fos = new FileOutputStream(file1);
byte[] bytes = new byte[5];
int len ;
while((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

(2)FileInputStream和FileOutputStream復制檔案的方法測驗
點擊查看代碼
//指定路徑下的檔案復制
public void copyFile(String srcPath,String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File file = new File(srcPath);
File file1 = new File(destPath);
fis = new FileInputStream(file);
fos = new FileOutputStream(file1);
byte[] bytes = new byte[1024];
int len ;
while((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test6(){
long start = System.currentTimeMillis();
String srcPath = "/Users/twq/Downloads/01.mp4";
String destPath = "/Users/twq/Downloads/03.mp4";
copyFile(srcPath,destPath);
long end = System.currentTimeMillis();
System.out.println("復制操作花費的時間為:"+(end - start));
}


3.緩沖流-位元組流
(1)實作非文本檔案的復制
點擊查看代碼
/*
實作非文本檔案的復制
*/
@Test
public void test7() {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造檔案
File file = new File("QQ20210927-0.jpg");
File file1 = new File("QQ20210927-2.jpg");
//2.造流
//2.1造節點流
fis = new FileInputStream(file);
fos = new FileOutputStream(file1);
//2.2造緩沖流:處理流是包裝在節點流之上的
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.復制的細節:讀取、寫入
byte[] bytes = new byte[1024];
int len;
while((len = bis.read(bytes))!= -1){
bos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//4.資源關閉
//要求:先關閉外層的流,在關閉內層的流
//關閉外層流的同時,內層流也會自動進行關閉,關于內層流的關閉我們可以省略
// fos.close();
// fis.close();
}

(2)緩沖流相較于節點流的優勢
點擊查看代碼
/*
實作非文本檔案的復制
*/
@Test
public void test7() {
long start = System.currentTimeMillis();
String srcPath = "/Users/twq/Downloads/01.mp4";
String destPath = "/Users/twq/Downloads/02.mp4";
copyFileBuffer(srcPath,destPath);
long end = System.currentTimeMillis();
System.out.println("緩沖流復制操作花費的時間為:"+(end - start));
}
//指定路徑下的檔案復制
public void copyFileBuffer(String srcPath,String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造檔案
File file = new File(srcPath);
File file1 = new File(destPath);
//2.造流
//2.1造節點流
fis = new FileInputStream(file);
fos = new FileOutputStream(file1);
//2.2造緩沖流:處理流是包裝在節點流之上的
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.復制的細節:讀取、寫入
byte[] bytes = new byte[1024];
int len;
while((len = bis.read(bytes))!= -1){
bos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//4.資源關閉
//要求:先關閉外層的流,在關閉內層的流
//關閉外層流的同時,內層流也會自動進行關閉,關于內層流的關閉我們可以省略
// fos.close();
// fis.close();
}



緩沖流能提高讀寫速度的原因:內部提供了一個緩沖區
4.緩沖流-字符流
使用BufferReader和BufferWriter實作文本檔案的復制點擊查看代碼
//使用BufferReader和BufferWriter實作文本檔案的復制
@Test
public void test8() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//創建檔案和相應的流
br = new BufferedReader(new FileReader(new File("hello.txt")));
bw = new BufferedWriter(new FileWriter(new File("hello3.txt")));
//讀
char[] chars = new char[1024];
int len ;
while((len = br.read(chars))!= -1){
bw.write(chars,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

5.圖片的加解密
相同的代碼在運行一次就可以進行解密,主要是因為兩次相同的異或之后可以得到運來的資料
6.轉換流
(1)InputStreamReader和OutputStreamWriter都屬于字符流,作用都是提供位元組流與字符流之間的轉換①InputStreamReader:將一個位元組的輸入流轉換為字符的輸入流
點擊查看代碼
@Test
public void test() {
InputStreamReader isr = null;
try {
FileInputStream fis = new FileInputStream("hello.txt");
// InputStreamReader isr = new InputStreamReader(fis);//使用系統默認的字符集
//引數2指明了字符集,具體使用那個字符集,取決于檔案hello.txt保存時使用的字符集
isr = new InputStreamReader(fis,"UTF-8");
char[] chars = new char[20];
int len ;
while((len = isr.read(chars))!= -1){
String s = new String(chars, 0, len);
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(isr != null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

②OutputStreamWriter:將一個字符的輸出流轉為位元組的輸出流
(2)綜合使用InputStreamReader和OutputStreamWriter
點擊查看代碼
@Test
public void test1(){
InputStreamReader isr = null;
OutputStreamWriter osw = null;
try {
File file = new File("hello.txt");
File file1 = new File("hello4.txt");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(file1);
isr = new InputStreamReader(fis);
osw = new OutputStreamWriter(fos,"gbk");
char[] chars = new char[20];
int len;
while((len = isr.read(chars)) != -1){
osw.write(chars,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(isr != null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(osw != null){
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

7.資料流
(1)DataInputStream 和 DataOutputStream作用:擁有讀取或寫出基本資料型別的變數或字串點擊查看代碼
將檔案中存盤的基本資料型別變數和字串讀取到記憶體中,保存在變數中
注意點:讀取不同型別的資料要與當初寫入檔案時,保存的資料的順序一致!
*/
@Test
public void test3() {
DataInputStream dis = null;
try {
dis = new DataInputStream(new FileInputStream("data.txt"));
String name = dis.readUTF();
int age = dis.readInt();
boolean isMale = dis.readBoolean();
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("isMale = " + isMale);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(dis != null){
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() {
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("唐昊");
dos.flush();//重繪操作,將記憶體中的資料寫入檔案
dos.writeInt(23);
dos.flush();
dos.writeBoolean(true);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(dos != null){
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

注意:需要先運行向檔案里寫的操作,才能繼續運行讀的操作,并且讀的順序必須與寫的順序一致,否則就會報EOFException例外
8.物件流
(1)ObjectInputStream和ObjectOutputStream:用于存盤和讀取基本資料型別資料或物件的處理流
①序列化與反序列化
點擊查看代碼
/*
反序列化:將磁盤檔案的物件還原為記憶體中的一個Java物件
使用ObjectInputStream來實作
*/
@Test
public void test6(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("Object.txt"));
Object o = ois.readObject();
String str = (String)o;
Person p =(Person) ois.readObject();
System.out.println(str);
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
序列化程序:將記憶體中的Java物件保存到磁盤中或通過網路傳輸出去
使用ObjectOutputStream實作
*/
@Test
public void test5(){
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("Object.txt"));
oos.writeObject(new String("北京天安門"));
oos.flush();//重繪操作
//要想一個Java物件時可序列化的,需要滿足相應的要求,見Person.java
oos.writeObject(new Person("王名",23));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
②自定義類的序列化與反序列化
Person類代碼如下點擊查看代碼
package com.Tang.io;
import java.io.Serializable;
/*
Person需要滿足如下的要求,方可序列化
1.需要實作介面:Seriallizabe
2.當前類提供一個全域常量:serialVersionUID
3.除了當前Person類需要實作Serializable介面之外,還必須保證其內部所有屬性也必須是可序列化的(默認情況下:基本資料型別可序列化
*/
public class Person implements Serializable {
public static final long serialVersionUID = 3476465475L;
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

注:代碼的運行得先運行序列化的代碼然后再運行反序列化的代碼
③public static final long serialVersionUID :這個id如果沒有寫的話,就進行的序列化操作(沒有進行反序列化),然后對類進行一些修改之后,在進行反序列化就會報錯,起初定義好序列化id是為了反序列化能根據此id進行無差錯的反序列化
9.RandomAccessFile的使用
(1)實作非文本檔案的復制
點擊查看代碼
/*
RandomAccessFile的使用
1.RandomAccessFile直接繼承與Java.lang.object類,實作了DataInput和DataOutput介面
2.RandomAccessFile既可以作為一個輸入流,又可以作為一個輸出流
*/
@Test
public void test7(){
RandomAccessFile raf = null;
RandomAccessFile rw = null;
try {
raf = new RandomAccessFile(new File("hello.txt"), "r");
rw = new RandomAccessFile(new File("hello1.txt"), "rw");
byte[] bytes = new byte[1024];
int len;
while((len = raf.read(bytes))!= -1){
rw.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(raf != null){
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(rw != null){
try {
rw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)單獨作為輸出流時
點擊查看代碼
/*
如果RandomAccessFile作為輸出流時,寫出到的檔案如果不存在,則在執行程序中自動創建
如果寫到的檔案存在,則會對原有檔案從頭開始覆寫
*/
@Test
public void test8(){
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(new File("hello.txt"),"rw");
raf.write("xyz".getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
if(raf != null){
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

上述代碼運行之后hello.txt 中的內容如下

(3)實作在檔案指定位置插入資料
點擊查看代碼
@Test
public void test8(){
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(new File("hello.txt"),"rw");
raf.seek(3);//將指標調到角標為3的位置
//保存指標3后面的所有資料到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] bytes = new byte[20];
int len;
while((len = raf.read(bytes))!= -1){
builder.append(new String(bytes,0,len));
}
//調回指標寫入"xyz"
raf.seek(3);
raf.write("xyz".getBytes());
//將StringBuilder 中的資料寫入到檔案中
raf.write(builder.toString().getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
if(raf != null){
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

運行代碼在檔案內容角標為3的位置插入xyz之后結果如下

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/498689.html
標籤:Java
上一篇:在Spring Boot中如何使用@ConfigurationProperties系結配置引數呢?
下一篇:Java面試題(三)--虛擬機
