文章目錄
- Day 17
- IO流
- IO流的異常處理
- IO流的經典算法
Day 17
2019年5月18日。
這是我學習Java的第十七天。
這一天,我學到了以下的知識。
IO流
IO流,用來處理裝置之間的資料傳輸,Java對資料的操作是通過流的方式,而Java用于操作流的對象都在IO包中
IO流按照資料流向,可分為:輸入流(從硬碟讀取資料到記憶體),輸出流(從記憶體寫入資料到硬碟)
IO流按照資料類型,可分為:
-
位元組流
可以讀寫任何類型的檔案,比如音頻、視訊、文本檔案
抽象基類如下:
-
InputStream
常用具體子類:1.FileInputStream
構造方法:
FileInputStream(File file)
:通過打開一個到實際檔案的連接配接來建立一個 FileInputStream,該檔案通過檔案系統中的 File 對象 file 指定
FileInputStream(String name)
:通過打開一個到實際檔案的連接配接來建立一個 FileInputStream,該檔案通過檔案系統中的路徑名 name 指定
常用的成員方法
- 讀取功能
-
int read(byte[] b)
:一次讀取一個位元組數組
- 當該方法傳回 -1 時,表明已經讀完了資料。一般可用該值來判斷資料是否已經周遊完成
- 關閉功能
-
:關閉檔案流,釋放資源public void close() throws IOException
2.BufferedInputStream
為了對應BufferedOutputStream,Java提供了BufferedInputStream
構造方法:
BufferedInputStream(InputStream in)
:建立一個 BufferedInputStream 并儲存其參數,即輸入流 in,以便将來使用
-
OutputStream
常用具體子類:1.FileOutputStream
構造方法:
FileOutputStream(File file)
:建立一個向指定 File 對象表示的檔案中寫入資料的檔案輸出流
FileOutputStream(String name)
:建立一個向具有指定名稱的檔案中寫入資料的輸出檔案流
常用的成員方法
- 寫入功能
-
:寫一個位元組 超過一個位元組 砍掉前面的位元組public void write(int b)
-
:寫一個位元組數組public void write(byte[] b)
-
:寫一個位元組數組的一部分public void write(byte[] b,int off,int len)
- 關閉功能
-
public void close() throws IOException
:關閉檔案流,釋放資源
面試題:為什麼一定要close()?
a: 通知系統釋放關于管理a.txt檔案的資源
b: 讓Io流對象變成垃圾,等待垃圾回收器對其回收
2.BufferedOutputStream
位元組流一次讀寫一個數組的速度,明顯比一次讀寫一個位元組的速度快很多,這是加入了數組這樣的緩沖區效果,java本身在設計的時候,也考慮到了這樣的設計思想(裝飾設計模式後面講解),是以提供了位元組緩沖區流,即BufferedOutputStream
構造方法:
BufferedOutputStream(OutputStream out)
:建立一個新的緩沖輸出流,以将資料寫入指定的底層輸出流
-
字元流
隻能讀寫文本檔案
由于位元組流操作中文不是特别友善,是以,java就提供了字元流
介紹字元流之前,首先介紹編碼和解碼的概念:
-
編碼
- 把一個字元串轉換成一個位元組數組
-
public byte[] getBytes()
:使用平台的預設字元集将此 String編碼為 byte 序列,并将結果存儲到一個新的 byte 數組中
-
:使用指定的字元集将此 String 編碼為 byte 序列,并将結果存儲到一個新的 byte 數組中public byte[] getBytes(String charsetName)
-
解碼
- 把位元組數組轉換成字元串
-
public String(byte[] bytes)
:通過使用平台的預設字元集解碼指定的 byte 數組,構造一個新的 String
-
:通過使用指定的 charset 解碼指定的 byte 數組,構造一個新的 Stringpublic String(byte[] bytes, String charsetName)
抽象基類如下:
-
Writer
常用具體子類:1.OutputStreamWriter——FileWriter(便攜類)
構造方法:
OutputStreamWriter(OutputStream out)
:根據預設編碼(GBK)把位元組流的資料轉換為字元流
OutputStreamWriter(OutputStream out,String charsetName)
:根據指定編碼把位元組流資料轉換為字元流
常用的成員方法
- 寫入功能
-
:寫一個字元public void write(int c)
-
:寫一個字元數組public void write(char[] cbuf)
-
:寫一個字元數組的一部分public void write(char[] cbuf,int off,int len)
-
:寫一個字元串public void write(String str)
-
:寫一個字元串的一部分public void write(String str,int off,int len)
2.BufferedWriter
高效的字元輸出流
構造方法:
public BufferedWriter(Writer w)
:建立一個使用預設大小輸出緩沖區的緩沖字元輸出流
特殊方法:
public void newLine()
:根據系統來決定換行符,具有系統相容性的換行符l
-
Reader
常用具體子類:1.InputStreamReader——FileReader(便攜類)
構造方法:
InputStreamReader(InputStream is)
:用預設的編碼(GBK)讀取資料
InputStreamReader(InputStream is,String charsetName)
:用指定的編碼讀取資料
常用的成員方法
- 讀取功能
-
:一次讀取一個字元public int read()
-
:一次讀取一個字元數組,如果沒有讀到,則傳回-1public int read(char[] cbuf)
2.BufferedReader
高效的字元輸入流
構造方法:
public BufferedReader(Reader e)
:建立一個使用預設大小輸入緩沖區的緩沖字元輸入流
特殊方法:
public String readLine()
:一次讀取一行資料 ,是以換行符為标記的,讀到換行符就換行,沒讀到資料傳回null
IO流的異常處理
-
位元組流
以FileOutputStream為例,代碼如下
public class MyTest {
public static void main(String[] args) {
//流的異常處理
FileOutputStream out = null;
try {
out = new FileOutputStream("d.txt");
out.write(100);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 字元流
public class MyTest {
public static void main(String[] args) {
//處理流的異常
//一次多寫一些
InputStreamReader in = null;
OutputStreamWriter out = null;
try {
in = new InputStreamReader(new FileInputStream("MyTest.java"));
out = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\MyTest.java"));
//定義一個字元緩沖區
char[] chars = new char[2000];
int len = 0;//記錄每次讀取到的有效字元個數
while ((len = in.read(chars)) != -1) {
out.write(chars, 0, len);
out.flush();
}
} catch (IOException e) {
//處理邏輯,預設列印異常的詳細堆棧資訊
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
IO流的經典算法
-
ArrayList集合中的字元串資料存儲到文本檔案中,以及将文本檔案中的資料反向讀入到ArrayList集合中
代碼如下
//1.ArrayList集合中的字元串數組存儲到文本檔案
public class MyTest {
public static void main(String[] args) throws IOException {
//需求:把ArrayList集合中的字元串資料存儲到文本檔案
ArrayList<String> list = new ArrayList<>();
list.add("馮小剛");
list.add("張藝謀");
list.add("甯浩");
list.add("徐峥");
list.add("小四");
//把集合中的資料儲存到檔案檔案中
//思路,周遊集合,取出資料寫入文本檔案
BufferedWriter writer = new BufferedWriter(new FileWriter("username.txt"));
for (String s : list) {
writer.write(s);
writer.newLine();
writer.flush();
}
writer.close();
}
}
//2.文本檔案中的資料反向讀入到ArrayList集合
public class MyTest2 {
public static void main(String[] args) throws IOException {
//需求是,把文本檔案中的資料讀取到集合中
ArrayList<String> list = new ArrayList<>();
BufferedReader reader = new BufferedReader(new FileReader("username.txt"));
while (true){
String s = reader.readLine();
if(s!=null){
list.add(s);
}else{
break;
}
}
System.out.println(list);
}
}
-
多級檔案夾複制
代碼如下
public class HomeTest {
public static void main(String[] args) throws IOException {
//需求:複制多級檔案夾
//1.封裝源檔案夾
File srcFolder = new File("C:\\test2");
//2.封裝目标檔案夾
File targetFolder = new File("D:\\test2");
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
//進行複制
copyFolder(srcFolder, targetFolder);
System.out.println("複制完成");
}
private static void copyFolder(File srcFolder, File targetFolder) throws IOException {
//周遊源檔案夾下,所有的檔案,複制到目标檔案夾下去
File[] files = srcFolder.listFiles();
for (File f : files) {
if(f.isFile()){
copyFiles(f, targetFolder);
}else{
//targetFolder = new File(targetFolder.getPath() + "\\" + f.getName());
//遞歸
File file = new File(targetFolder,f.getName());
if (!file.exists()) {
file.mkdirs();
}
copyFolder(f, file);
}
}
}
//複制檔案
private static void copyFiles(File f, File targetFolder) throws IOException {
//使用位元組流來複制
FileInputStream in = new FileInputStream(f);//封裝源檔案
//封裝目标檔案
//File file = new File(targetFolder, f.getName());
//System.out.println(file);
FileOutputStream out = new FileOutputStream(new File(targetFolder, f.getName()));
int len = 0;
byte[] bytes = new byte[1024 * 8];
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
out.flush();
}
//是否資源
in.close();
out.close();
}
}
-
錄入學生資訊到檔案中
代碼如下
//學生類
public class Student implements Comparable<Student>{
private String name;
private int score;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.score = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return score;
}
public void setAge(int age) {
this.score = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", grade=" + score +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return score == student.score &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, score);
}
@Override
public int compareTo(Student o) {
int num=this.score-o.score;
int num2=num==0?this.name.compareTo(o.name):num;
return num2;
}
}
//測試類
public class HomeTest {
public static void main(String[] args) throws IOException {
//需求: 鍵盤錄入學生資訊按照總分排序并寫入文本檔案
Scanner scanner = new Scanner(System.in);
Student student;
TreeSet<Student> treeSet = new TreeSet<>();
BufferedWriter buf = new BufferedWriter(new FileWriter("Student.txt"));
for (int i = 1; i < 4; i++) {
scanner = new Scanner(System.in);
student = new Student();
System.out.println("請輸入第" + i + "位學生的姓名");
String name = scanner.nextLine();
student.setName(name);
System.out.println("請輸入第" + i + "位學生的成績");
int score = scanner.nextInt();
student.setAge(score);
treeSet.add(student);
}
buf.write(treeSet.toString());
buf.close();
}
}