一嘹黔、File類
public static void test(){
//File src = new File("C:/Users/yj/Desktop/1.txt");
File src = new File("1.txt");
System.out.println(src.getName());
System.out.println(src.getPath());//如果是絕對路徑账嚎,否則返回相對路徑
System.out.println(src.getAbsolutePath());//返回絕對路徑
System.out.println(src.getParent());//返回上一級目錄,如果是相對路徑,沒有上一級返回空
System.out.println("是否是絕對路徑: " + src.isAbsolute());
}
//判斷信息
public static void test1(){
//File src = new File("1.txt");
File src = new File("C:/Users/yj/Desktop/1.txt");
System.out.println("文件是否存在:" + src.exists());
System.out.println("文件是否可寫: " + src.canWrite());
System.out.println("是不是文件夾: " + src.isDirectory());
System.out.println("是不是文件: " + src.isFile());
System.out.println("文件的長度: " + src.length());//只有文件才能讀取長度
}
說明:以上是File
類的一些常用方法郭蕉。下面我們看File
中對目錄的操作方法:
mkdir()創(chuàng)建目錄疼邀,必須確保父目錄存在,否則創(chuàng)建失敗
mkdirs()召锈,創(chuàng)建目錄旁振,如果父目錄不存在,也一同創(chuàng)建
list()以字符串形式列出所有文件和目錄名字(不包含路徑)
listFiles()以字符串形式列出所有文件和目錄名字(包含完整路徑)
static listRoots()根路徑
二烟勋、流(stream)
2.1 概念
程序與文件规求、數(shù)組、網(wǎng)絡(luò)連接卵惦、數(shù)據(jù)庫都是使用流進(jìn)行交互,但是都是以程序?yàn)橹行?/strong>瓦戚。
2.2 分類
- 1沮尿、根據(jù)流向:輸入流和輸出流
- 2、根據(jù)數(shù)據(jù)類型:字節(jié)流(二進(jìn)制较解,可以處理任何數(shù)據(jù))和字符流(文本畜疾,只能處理純文本)
- 3、根據(jù)功能:節(jié)點(diǎn)流印衔,就是離數(shù)據(jù)源最近的啡捶,包裹源頭的;處理流奸焙,是增強(qiáng)功能瞎暑,提高性能的。
2.3 字符流和字節(jié)流
2.3.1 字節(jié)流
輸入流:InputStream
(抽象類)(常用實(shí)現(xiàn)類FileInputStream
)
public int read(byte[] b)
public int read(byte[] b, int off, int len)
public void close()
輸出流:OutputStream
(抽象類)(常用實(shí)現(xiàn)類FileOutputStream
)
public void write(byte[] b)
public void write(byte[] b,int off,int len)
public void flush()
public void close()
下面看使用字節(jié)流讀取文件的基本步驟:
package cn.itcast.day146.stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
//文件的讀取
public class Demo01 {
public static void main(String[] args) {
//1与帆、建立聯(lián)系
File src = new File("D:/FQ/parent/FeiqCfg.xml");
//2了赌、選擇流
InputStream is = null;//提升作用域
try {
is = new FileInputStream(src);
//3、操作玄糟,不斷讀取
byte[] buffer = new byte[1024];//相當(dāng)于一個緩沖數(shù)組勿她,即每次讀取的字節(jié)數(shù)不超過1024個
int len = 0;//接收實(shí)際讀取的大小
//循環(huán)讀取,每次讀取1024個字節(jié)
while((len = is.read(buffer)) != -1){
//輸出阵翎,需要將字節(jié)數(shù)組轉(zhuǎn)換成字符串
String info = new String(buffer , 0, len);
System.out.println(info);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在");
} catch (IOException e) {
e.printStackTrace();
System.out.println("讀取文件失敗");
}finally{
//4逢并、釋放資源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("關(guān)閉輸入流失敗");
}
}
}
}
}
下面我們看使用字節(jié)流寫入文件的基本步驟:
package cn.itcast.day146.stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//寫出文件
public class Demo02 {
public static void main(String[] args) {
//1、建立聯(lián)系
File dest = new File("D:/FQ/parent/test.txt");
//2郭卫、選擇流
OutputStream os = null;
try {
os = new FileOutputStream(dest, true);//寫出文件砍聊,以追加的形式
//3、操作
String str = "something is so difficult \r\n";
//字符串轉(zhuǎn)換成字節(jié)數(shù)組
byte[] data = str.getBytes();
os.write(data, 0, data.length);
os.flush();//刷新箱沦, 如果使用close方法會默認(rèn)調(diào)用此方法
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件未找到");
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件寫出失敗");
}finally{
try {
if(os != null){
os.close();//釋放資源
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("關(guān)閉輸出流失敗");
}
}
}
}
說明:寫入文件的基本步驟較為簡單辩恼,首先將要寫入的內(nèi)容轉(zhuǎn)換成字節(jié)數(shù)組,然后使用write
方法一次性寫入即可。同時我們在關(guān)閉流之前最好手動刷新緩存灶伊,雖然關(guān)閉流的時候會自動刷新疆前。我們將讀取和寫入結(jié)合起來就可以實(shí)現(xiàn)文件的拷貝了:
public static void fileCopy02(String srcPath, String destPath){
// 1、創(chuàng)建源(文件必須存在)+目的地(文件可以不存在)
File src = new File(srcPath);
File dest = new File(destPath);
// 2聘萨、選擇流
try (InputStream is = new FileInputStream(src);
OutputStream os = new FileOutputStream(dest);) {
// 3竹椒、文件拷貝=讀取+寫出
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {// 讀取
// 寫出
os.write(buffer, 0, len);
}
os.flush();
}catch (Exception e) {
e.printStackTrace();
}
}
說明:這里要注意的是文件源必須存在,而目的地可以不存在米辐,同時這里我們使用了1.7的新特性胸完,即try with
,內(nèi)部會幫我們關(guān)閉流翘贮。
2.3.2 字符流
輸入流:Reader
(抽象類)(常用實(shí)現(xiàn)類FileReader
)
public int read(char[] cbuf)
public abstract int read(char[] cbuf,int off,int len)
public abstract void close()
輸出流:Writer
(抽象類)(常用實(shí)現(xiàn)類FileWriter
)
public void write(char[] cbuf)
public abstract void write(char[] cbuf,int off,int len)
public abstract void close()
public void write(String str,int off,int len)
下面我們給出使用字符流讀取文件的基本步驟:
package cn.itcast.day146.stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
//文件的讀取赊窥,使用字符流
public class Demo04 {
public static void main(String[] args) {
//創(chuàng)建源
File src = new File("D:/FQ/parent/test.txt");
//選擇流
Reader reader = null;
try {
reader = new FileReader(src);
char[] buffer = new char[1024];
int len = 0;
try {
while((len = reader.read(buffer)) != -1){
//字符數(shù)組轉(zhuǎn)換成字符串
String str = new String(buffer, 0, len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件讀取失敗");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("源文件不存在");
}finally{
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
說明:這里可以看到和使用字節(jié)流讀取基本一樣,只是使用的是字符數(shù)組狸页。下面看使用字符流寫入文件:
package cn.itcast.day146.stream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//使用字符流寫出文件
public class Demo05 {
public static void main(String[] args) {
//創(chuàng)建源
File src = new File("F:/FQ/parent/test.txt");
//選擇流
Writer writer = null;
try {
writer = new FileWriter(src, true);//第二個參數(shù)為true表示追加
//寫出
String msg = "狗蛋打了鐵柱一頓";
writer.write(msg);//這里可以直接寫字符串
writer.append("狗蛋");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
說明:這里要注意的是在字符流沒有關(guān)閉的情況下我們可以直接使用append
方法進(jìn)行寫入锨能。使用字符流進(jìn)行文件的拷貝這里就不給出了。
2.4 緩沖流
緩沖流主要用于增強(qiáng)功能芍耘,提高性能址遇。處理流一定要在節(jié)點(diǎn)流之上。我們推薦使用緩沖流斋竞,而不是直接使用節(jié)點(diǎn)流倔约。
2.4.1字節(jié)緩沖流
針對字節(jié)的緩沖流,主要實(shí)現(xiàn)類有:
BufferedInputStream:沒有新增方法
BufferedOutputStream: 沒有新增方法
下面我們看使用的基本步驟:
package cn.itcast.day146.stream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/*
* 文件拷貝坝初,使用緩沖字節(jié)流浸剩,建議使用,提高性能
* 只是在節(jié)點(diǎn)流上面包上一層緩沖流
* */
public class Demo06 {
public static void fileCopy(String srcPath, String destPath) throws FileNotFoundException, IOException {
File src = new File(srcPath);
File dest = new File(destPath);
if(!src.isFile()){
System.out.println("只能拷貝文件");
throw new IOException("只能拷貝文件");
}
//如果目的地為已經(jīng)存在的文件夾脖卖,不能建立與文件夾同名的文件或文件夾乒省,當(dāng)然如果是file則會覆蓋
if(dest.isDirectory()){
System.out.println("能建立與文件夾同名的文件或文件夾");
throw new IOException("能建立與文件夾同名的文件或文件夾");
}
//2、選擇流
InputStream is = new BufferedInputStream(new FileInputStream(src));
OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
//3畦木、文件拷貝=讀取+寫出
byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1){//讀取
os.write(buffer, 0, len);//寫出
}
os.flush();
//關(guān)閉:先打開的后關(guān)閉
os.close();
is.close();
}
}
說明:可以看到使用步驟和之前的字節(jié)流基本是一致的袖扛,只是我們使用緩沖流對字節(jié)流進(jìn)行了包裝,用以提高讀取和寫入的性能十籍。
2.4.2 字符緩沖流
針對字符的緩沖流蛆封,主要實(shí)現(xiàn)類有:
BufferedReader:新增方法:readLine()
BufferedWriter:新增方法:newLine()
下面我們看基本的使用步驟:
package cn.itcast.day146.stream;
//文件拷貝,使用緩沖字符流
//新增方法
public class Demo07 {
public static void main(String[] args) {
File src = new File("D:/FQ/parent/test.txt");
BufferedReader reader = null;//使用新增方法不能有多態(tài)勾栗,即定義的時候需要使用緩沖字符流
File dest = new File("D:/FQ/parent/test01.txt");
BufferedWriter writer = null;//使用新增方法不能有多態(tài)惨篱,即定義的時候需要使用緩沖字符流
try {
//包裝
reader = new BufferedReader(new FileReader(src));
writer = new BufferedWriter(new FileWriter(dest));
//使用之前的方式
// char[] buffer = new char[1024];
// int len = 0;
// while((len = reader.read(buffer)) != -1){
// writer.write(buffer, 0, len);
// }
//使用新增方法進(jìn)行讀取,使用新增方法不能有多態(tài)围俘,即定義的時候需要使用緩沖字符流
String line = null;
while((line = reader.readLine()) != null){//一行一行的讀取
writer.write(line);//寫出
writer.newLine();//加上換行符
}
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
說明:基本的使用步驟還是和之前一樣砸讳,當(dāng)然我們推薦使用新方法琢融,這樣比較簡單。
2.5 轉(zhuǎn)換流
將字節(jié)流轉(zhuǎn)換為字符流簿寂,用于處理亂碼問題漾抬。這里我們先看亂碼產(chǎn)生原因:
- 1)編碼與解碼的字符集不統(tǒng)一
- 2)字符缺少,長度丟失
常用實(shí)現(xiàn)類:
InputStreamReader
OutputStreamWriter
例如:
//亂碼原因一:解碼和編碼的字符集不統(tǒng)一
public static void test1() throws UnsupportedEncodingException {
String str = "中國";//utf-8
//編碼 char-->二進(jìn)制
byte[] data = str.getBytes();
//解碼和編碼的字符集統(tǒng)一
System.out.println(new String(data));//沒有亂碼
data = str.getBytes("gbk");//設(shè)定編碼字符集
//解碼和編碼的字符集不統(tǒng)一
System.out.println(new String(data));//有亂碼
//編碼
byte[] data2 = "中國".getBytes("UTF-8");
//解碼
str = new String(data2, "UTF-8");
System.out.println(str);
}
//亂碼原因二:字節(jié)數(shù)不完整導(dǎo)致亂碼
public static void test2(){
String str = "中國";
byte[] data = str.getBytes();
//字節(jié)數(shù)不完整導(dǎo)致亂碼
System.out.println(new String(data, 0, 3));
}
下面我們看轉(zhuǎn)換流的基本使用步驟:
/*轉(zhuǎn)換流:字節(jié)-->字符
* 1常遂、輸出流 OutputStreamWriter編碼
* 2纳令、輸入流 InputStreamReader解碼
* */
public class Demo09 {
public static void main(String[] args) throws IOException {
//可以在轉(zhuǎn)換流中指定解碼字符集,注意:這里的字符集就是我們要讀取文件的編碼字符集
BufferedReader br = new BufferedReader(
new InputStreamReader(/*這是一個轉(zhuǎn)換流克胳,將字符流和字節(jié)流聯(lián)系起來*/
new FileInputStream(new File("D:/FQ/parent/test.txt")), "UTF-8"));//底層是一個字節(jié)流
//寫出文件
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("D:/FQ/parent/test01.txt")), "UTF-8"));
char[] buffer = new char[1024];
int len = 0;
while((len = br.read(buffer)) != -1){
bw.write(buffer, 0, len);
}
bw.flush();
/*String info = null;
while(null != (info = br.readLine())){
System.out.println(info);
}
br.close();*/
br.close();
bw.close();
}
}
說明:這里我們知道轉(zhuǎn)換流是將字節(jié)流轉(zhuǎn)換成字符流平绩,所以底層包裝的是字節(jié)流,當(dāng)然這里我們還使用了緩沖流對字符流進(jìn)行了包裝漠另。這里我們使用字節(jié)流讀取捏雌,在讀取的時候進(jìn)行解碼,即將內(nèi)容轉(zhuǎn)換成了字節(jié)酗钞,而同時我們在寫入的時候也是將字符轉(zhuǎn)換成字節(jié)再寫入腹忽,這樣就不會出現(xiàn)亂碼的問題。
2.6 其他流
2.6.1 字節(jié)流
這里我們看字節(jié)數(shù)組流砚作,可將此流看作在其他電腦的內(nèi)存中,所以我們不用關(guān)閉嘹锁,關(guān)閉也是無效的葫录。其常用的實(shí)現(xiàn)類有:
ByteArrayInputStream
ByteArrayOutputStream
下面給出基本的使用步驟:
//輸入流操作與文件輸入流操作一致
public static void read(byte[] src) throws IOException{
//String msg = "輸入流操作與文件輸入流操作一致";
//byte[] src = msg.getBytes();
//選擇流
InputStream is = new BufferedInputStream(new ByteArrayInputStream(src));
//操作
byte[] buffer = new byte[1024];
int len = 0;
while(-1 != (len = is.read(buffer))){
System.out.println(new String(buffer, 0, len));
}
is.close();
}
//輸出流與文件輸出流有些不同,因?yàn)橛行略龇椒旎荒苁褂枚鄳B(tài)
public static byte[] write() throws IOException{
//目的地
byte[] dest;
//選擇流米同,不同點(diǎn)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//寫出
String msg = "輸入流操作與文件輸入流操作一致";
byte[] info = msg.getBytes();
bos.write(info, 0, info.length);
//獲取數(shù)據(jù)
dest = bos.toByteArray();
bos.close();
return dest;
}
說明:這里我們只是給出了讀寫的方法,并沒有說從哪里讀取摔竿,寫到哪里去面粮,這是因?yàn)樵谑褂么祟惲鞯臅r候需要明白,比如在文件拷貝的時候继低,是按照這樣一個步驟進(jìn)行熬苍,首先是將文件內(nèi)容拷貝到程序中,之后再從程序中拷貝到文件中袁翁,下面我們給出例子:
package cn.itcast.day146.stream;
import java.io.*;
/*
* 使用字節(jié)數(shù)組流讀取寫出文件
* 1柴底、文件-->程序-->字節(jié)數(shù)組
* 文件輸入流+字節(jié)數(shù)組輸出流
*
* 2、字節(jié)數(shù)組-->程序-->文件
* 字節(jié)數(shù)組輸入流+文件輸出流
* */
public class Demo11 {
public static void main(String[] args) throws IOException {
byte[] data = getBytesFromFile("D:/FQ/parent/test.txt");
toFileFromByteArray(data, "D:/FQ/parent/test01.txt");
}
//文件-->程序
public static byte[] getBytesFromFile(String stcPath) throws IOException{
//創(chuàng)建源(文件)和目的地(字節(jié)數(shù)組)
File src = new File(stcPath);
byte[] dest = null;
//選擇流
//文件輸入流
InputStream is = new BufferedInputStream(new FileInputStream(src));
//字節(jié)數(shù)組輸出流粱胜,不能使用多態(tài)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//操作:不斷讀取文件柄驻,寫出到字節(jié)數(shù)組流中
byte[] buffer = new byte[1024];
int len = 0;
while(-1 != (len = is.read(buffer))){
//寫出到字節(jié)數(shù)組流中
bos.write(buffer, 0, len);
}
bos.flush();
//獲取數(shù)據(jù)
dest = bos.toByteArray();//將字節(jié)數(shù)組流中的數(shù)據(jù)寫到一個字節(jié)數(shù)組中
bos.close();
is.close();
return dest;
}
public static void toFileFromByteArray(byte[] src, String destPath) throws IOException{
//創(chuàng)建源,即src
//創(chuàng)建目的地焙压, 即dest
File dest = new File(destPath);
//選擇流
//字節(jié)數(shù)組輸入流
InputStream is = new BufferedInputStream(new ByteArrayInputStream(src));
//文件輸出流
OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
//不斷讀取
byte[] buffer = new byte[1024];
int len = 0;
while(-1 != (len = is.read(buffer))){
os.write(buffer, 0, len);//寫出到文件中
}
os.flush();
os.close();
is.close();
}
}
說明:這里要注意的是此類流由于數(shù)組的大小有限鸿脓,所以只適合讀取少量數(shù)據(jù)的文件抑钟。同時我們不管在讀取還是寫的時候一定是以程序?yàn)橹行模@樣就不至于分不清到底是使用輸入流還是輸出流了野哭。
2.6.2 處理流
這里我們先給出DataInputStream
和DataOutputStream
兩個流在塔,這個類型的流可以保留數(shù)據(jù)和數(shù)據(jù)類型,比如可以直接讀取String
類型數(shù)據(jù)虐拓,并保留其類型心俗。但是這個類有個限制就是讀取和寫入的順序必須一致。下面給出基本的使用步驟:
public static void write(String destPath) throws IOException{
double point = 2.5;
long num = 100L;
String str = "數(shù)據(jù)類型";
//創(chuàng)建源
File dest = new File(destPath);
//選擇流 DataInputStream
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream(dest)));
//操作蓉驹,寫出城榛,同時寫出的順序和讀取的順序必須一致
dos.writeDouble(point);
dos.writeLong(num);
dos.writeUTF(str);
dos.flush();
dos.close();
}
//讀取數(shù)據(jù)加類型
public static void read(String srcPath) throws IOException{
//創(chuàng)建源
File src = new File(srcPath);
//選擇流
DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(src)));
//操作,讀取的順序必須和寫出的數(shù)據(jù)一致态兴, 必須存在才能讀取
double num1 = dis.readDouble();
long num2 = dis.readLong();
String str = dis.readUTF();
System.out.println(str);
}
說明:這個類型的流了解即可狠持。這里是對基本數(shù)據(jù)類型的處理流,下面我們看引用類型的處理流瞻润。
反序列化(輸入流)ObjectInputStraem : readObject()
序列化(輸出流)ObjectOutputStream : writeObject()
首先我們給出一個javabean
:
package cn.itcast.day159.stream;
import java.io.Serializable;
//序列化的類
public class Employee implements Serializable{
private transient String name ;//此屬性不進(jìn)行序列化
private double salary ;
public Employee() {
super();
}
public Employee(String name, double salary) {
super();
this.name = name;
this.salary = salary;
}
//getters and setters method
}
下面我們看基本的操作步驟:
package cn.itcast.day159.stream;
import java.io.*;
import java.util.Arrays;
public class Demo01 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//write("F:/FQ/parent/data.txt");
read("F:/FQ/parent/data.txt");
}
//序列化
public static void write(String destPath) throws IOException{
Employee employee = new Employee("Tom", 10000);
int[] arr = {1,2,3,4,5};//數(shù)組內(nèi)部實(shí)現(xiàn)了序列化接口
//創(chuàng)建源
File dest = new File(destPath);
//選擇流 DataInputStream
ObjectOutputStream dos = new ObjectOutputStream(new BufferedOutputStream(
new FileOutputStream(dest)));
//操作喘垂,寫出,同時寫出的順序和讀取的順序必須一致
dos.writeObject(employee);
dos.writeObject(arr);
dos.flush();
dos.close();
}
//反序列化
public static void read(String srcPath) throws IOException, ClassNotFoundException{
//創(chuàng)建源
File src = new File(srcPath);
//選擇流
ObjectInputStream dis = new ObjectInputStream(
new BufferedInputStream(new FileInputStream(src)));
//操作绍撞,讀取的順序必須和寫出的數(shù)據(jù)一致正勒, 必須存在才能讀取
Object obj = dis.readObject();
if(obj instanceof Employee){
Employee e = (Employee) obj;
//這里名字是取不到的,因?yàn)槲覀儧]有序列化此屬性
System.out.println("名字: " + e.getName() + "傻铣, 薪水: " + e.getSalary());
}
int arr[] = (int[]) dis.readObject();
System.out.println(Arrays.toString(arr));
}
}
說明:我們在類中使用關(guān)鍵字transient
限定那些字段不進(jìn)行序列化章贞,同時在測試的時候注意寫入在進(jìn)行讀取。
注意:
- 1非洲、反序列化必須和序列化順序一致鸭限,先序列化后反序列化
- 2、不是所有的對象都可以序列化,必須實(shí)現(xiàn)接口
java.io.Serializable
- 3、不是所有的屬性都需要序列化矢劲,不想序列化的屬性使用
transient
標(biāo)識