Java中文件操作和IO的實(shí)例練習(xí)
文件的基本概念
狹義上問文件,針對(duì)硬盤這種I/O設(shè)備的存儲(chǔ)
隨著文件變多,為了更好的管理,就按照層級(jí)結(jié)構(gòu)對(duì)文件進(jìn)行組織(也就是樹形結(jié)構(gòu)這種),這樣就有了文件夾或者目錄這種概念
一個(gè)文件夾中可以有多個(gè)文件,并且文件夾中也可以有文件夾,就這樣不斷層層嵌套,這樣的層級(jí)結(jié)構(gòu)

文件路徑(Path)
分為絕對(duì)路徑和相對(duì)路徑
絕對(duì)路徑:從樹型結(jié)構(gòu)的?度來看,樹中的每個(gè)結(jié)點(diǎn)都可以被?條從根開始,到達(dá)文件終點(diǎn)
相對(duì)路徑:可以從任意節(jié)點(diǎn),進(jìn)行路徑描述

這里再Windows中使用 \ 反斜杠進(jìn)行分割,其也可以使用 / 斜杠進(jìn)行分割,但反斜杠 \ 這種方式在代碼中需要進(jìn)行字符進(jìn)行轉(zhuǎn)義才可以使用,因此使用 / 斜杠最好


文件類型
文本文件和二進(jìn)制文件
文本文件:內(nèi)部存儲(chǔ)的內(nèi)容是"字符串",每一個(gè)部分都是一個(gè)"字符"(字符集/字符編碼)
二進(jìn)制文件:沒有限制,可以是任何數(shù)據(jù)
簡(jiǎn)單方法看文件是什么編碼
直接使用記事本打開,如果是亂碼,就是二進(jìn)制文件,不亂碼就是文本文件
File
屬性
| 類型 | 屬性 | 說明 |
|---|---|---|
| static String | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,String類型的表? |
| staticchar | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,char類型的表? |
構(gòu)造方法
| 簽名 | 說明 |
|---|---|
| File(File parent, String child) | 根據(jù)父目錄和子目錄,創(chuàng)建一個(gè)File實(shí)例 |
| File(String pathname) | 根據(jù)?件路徑創(chuàng)建?個(gè)新的File實(shí)例,路徑可以是絕對(duì)路徑或者相對(duì)路徑 |
| File(String parent,String child) | 根據(jù)??錄+孩??件路徑,創(chuàng)建?個(gè)新的File實(shí)例,??錄?路徑表? |
此時(shí)這里的File(String pathname)根據(jù)當(dāng)前目錄,其如果是相對(duì)目錄的話 就是想對(duì)當(dāng)前idea打開文件的路徑
方法



public class demo2 {
public static void main(String[] args) throws IOException {
File file = new File("d:/JAVA/Test/test.txt");
// File file = new File("./hello.txt");//這樣就會(huì)在java當(dāng)前文件中找是否有這個(gè)文件
System.out.println(file.getParent());//父目錄
System.out.println(file.getName());//文件名
System.out.println(file.getPath());//文件位置
System.out.println(file.getAbsoluteFile());
System.out.println(file.getCanonicalFile());
}
}

此時(shí)getAbsoluteFile()和getCanonicalFile()這個(gè)方法好像差不多,實(shí)則不然

這里getCanonicalFile()獲取信息更標(biāo)準(zhǔn),并且會(huì)把中間一些不必要的刪除

public class demo3 {
public static void main(String[] args) {
File file = new File("d:/JAVA/Test/hello.txt");
System.out.println(file.exists());//是否存在
System.out.println(file.isFile());//是否是一個(gè)普通文件
System.out.println(file.isDirectory());//是否是一個(gè)目錄
}
}

此時(shí)這個(gè)文件是一個(gè)普通文件,不是目錄,文件存在

file.delete();//刪除文件,直接從硬盤上刪除
public class demo3 {
public static void main(String[] args) {
File file = new File("d:/JAVA/Test/hello.txt");
System.out.println(file.exists());
//刪除文件
file.delete();
System.out.println(file.exists());
}
}


file.deleteOnExit();//也是刪除,JVM退出之前才進(jìn)行刪除
public class demo4 {
public static void main(String[] args) {
File file = new File("d:/JAVA/Test/test.txt");
System.out.println(file.exists());
file.deleteOnExit();//程序結(jié)束前刪除
System.out.println(file.exists());
//這里輸入會(huì)讓這個(gè)刪除滯后
Scanner sc = new Scanner(System.in);
sc.nextInt();
}
}
這里輸入會(huì)阻塞主線程,所以當(dāng)我輸入輸入未完成的時(shí)候,其文件還處于未刪除狀態(tài),當(dāng)輸入完成,后面沒有什么邏輯,其就會(huì)開始刪除了


String[] fileNames = file.list();//返回file目錄下所以文件名 并用String[]接收返回值
public class demo5 {
public static void main(String[] args) throws IOException {
File file = new File("d:/Java/python");
String[] fileNames = file.list();
if(fileNames == null){
System.out.println("空目錄");
return;
}
for(String fileName : fileNames){
System.out.println(fileName);
}
}
}
File[] files = file.listFiles(); //此時(shí)返回file目錄下所有文件,每一個(gè)文件用File表示
public class demo5 {
public static void main(String[] args) throws IOException {
File file = new File("d:/Java/python");
File[] files = file.listFiles();
if(files == null){
System.out.println("空目錄");
return;
}
for (File f : files){
System.out.println(file.getCanonicalFile());
}
}
}

file.mkdirs();//只可以創(chuàng)建一個(gè)當(dāng)前目錄 file.mkdirs();//如果創(chuàng)建過程中需要中間目錄也會(huì)進(jìn)行創(chuàng)建 返回值都是boolean
public class demo6 {
public static void main(String[] args) {
File file = new File("d:/Java/Test/aaa");
System.out.println(file.isDirectory());//判斷這個(gè)目錄是否存在
file.mkdir();//創(chuàng)建file對(duì)象的目錄
System.out.println(file.isDirectory());
}
}

public class demo6 {
public static void main(String[] args) {
File file = new File("d:/Java/Test/aaa/bbb/ccc");
System.out.println(file.isDirectory());//判斷這個(gè)目錄是否存在
file.mkdirs();//創(chuàng)建file對(duì)象的目錄,如果需要?jiǎng)?chuàng)建中間目錄,也會(huì)創(chuàng)建
System.out.println(file.isDirectory());
}
}

renameTo(File dest); //對(duì)文件進(jìn)行改名,相當(dāng)于文件的剪切和粘貼操作 //如果此時(shí)的目錄是./aaa/bbb/ccc,這里對(duì)aaa文件夾進(jìn)行改名是修改不了
public class demo7 {
public static void main(String[] args) {
File source = new File("d:/Java/Test/aaa");
File dest = new File("d:/Java/Test/mmm");
source.renameTo(dest);
}
}

文件讀寫-數(shù)據(jù)流(stream)
讀:就是把文件內(nèi)容數(shù)據(jù)讀取出來
寫:就是向文件夾中寫數(shù)據(jù)
分為兩個(gè)大類
1.字節(jié)流:讀寫以字節(jié)為單位,像這里InputStream輸入,OutputStream輸出
2.字符流:讀寫以字符為單位,像這里Reader輸入,Writer輸出
InputStream

read()讀取一個(gè)字節(jié)的數(shù)據(jù),返回-1表示讀完了 read(byte[] b),b是"輸出型參數(shù)" read(byte[] b,int off, int len)//從off偏移量開始讀取,讀len個(gè)字節(jié) -1表示的是讀到了文件末尾 注意:這里返回值都是int,因?yàn)?字節(jié)對(duì)齊"的概念,因?yàn)橛?jì)算機(jī)讀取4/8個(gè)字節(jié) 的效率大于讀取1/2個(gè)字節(jié)
InputStream是一個(gè)抽象類,因此不可以直接實(shí)例化對(duì)象,可以實(shí)例化FileInputStream對(duì)象

這里可能有FileNotFoundException異常,這個(gè)異常是IOException的子類


public class demo8 {
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("D:/JAVA/Test/test.txt");
while (true){
int n = inputStream.read();
if(n == -1){
break;//文件讀取完畢
}
System.out.printf("%x",n);
System.out.println();
}
}
}



上面這個(gè)是會(huì)不斷的讀取硬盤,每一個(gè)字節(jié)都會(huì)觸發(fā)一次read()讀取,并且讀取硬盤也比較慢,因此我們需要對(duì)其進(jìn)行優(yōu)化,并且還沒有使用close進(jìn)行文件關(guān)閉
關(guān)閉文件close()
在操作系統(tǒng)中有進(jìn)程,進(jìn)程中有個(gè)PCB里面有文件描述符表,每次打開文件,都會(huì)在這里進(jìn)行記錄,但是這個(gè)文件描述附表是不能自動(dòng)擴(kuò)容,因此如果打開文件過多,就放不下了,必須關(guān)閉文件其才會(huì)將其資源釋放出來
public class demo8 {
public static void main(String[] args){
InputStream inputStream = null;
try {
inputStream = new FileInputStream("D:/JAVA/Test/test.txt");
while (true){
//將這些數(shù)據(jù)放入1024數(shù)組中,可能超出
//因此這里采用存儲(chǔ),一次可以讀這么多的數(shù)據(jù)
byte[] bytes = new byte[1024];
int n = 0;
n = inputStream.read(bytes);
if(n == -1){
break;
}
for (int i = 0; i < n; i++) {
System.out.printf("%x\n",bytes[i]);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
//進(jìn)行資源釋放
if(inputStream != null){
try{
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}

上面這個(gè)代碼中try catch中又嵌套try catch,這樣的代碼十分的丑陋,因此 try with resources
public class demo8 {
public static void main(String[] args){
//上面還是try with resources語法解決上面問題
try (InputStream inputStream = new FileInputStream("D:/JAVA/Test/test.txt");){
while (true){
byte[] bytes = new byte[1024];
int n = inputStream.read(bytes);
if(n == -1){
break;
}
for (int i = 0; i < n; i++) {
System.out.printf("%x\n",bytes[i]);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

并且這里會(huì)自動(dòng)調(diào)用close


Scanner對(duì)字符讀取
上面讀取字符還是以byte單位進(jìn)行讀取,因此可以使用Scanner

public class demo12 {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("d:/Java/Test/test.txt")) {
Scanner scanner = new Scanner(inputStream,"UTF-8");
String s = scanner.next();
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
}
}

OutputStream


這里的OutputStream 仍然是一個(gè)抽象類,因此需要實(shí)例化FileOutputStream對(duì)象
public class demo9 {
public static void main(String[] args) {
try (OutputStream outputStream = new FileOutputStream("d:/Java/Test/test.txt")){
outputStream.write(65);
outputStream.write(66);
outputStream.write(67);
outputStream.write(68);
}catch (IOException e){
e.printStackTrace();
}
}
}
此時(shí)對(duì)這個(gè)文件進(jìn)行寫入


使用byte[]數(shù)組寫入
public class demo9 {
public static void main(String[] args) {
try (OutputStream outputStream = new FileOutputStream("d:/Java/Test/test.txt")){
// outputStream.write(65);
// outputStream.write(66);
// outputStream.write(67);
// outputStream.write(68);
byte[] bytes = {68,69,70,71};
outputStream.write(bytes);
}catch (IOException e){
e.printStackTrace();
}
}
}
此時(shí)法現(xiàn)一個(gè)問題,就是前面寫的ABCD好像被這次寫的覆蓋了
這里默認(rèn)是覆蓋寫

//將這個(gè)寫入變成追加寫
OutputStream outputStream = new FileOutputStream("d:/Java/Test/test.txt",true)
//將這個(gè)參數(shù)設(shè)置成true其就會(huì)變成追加寫
public class demo9 {
public static void main(String[] args) {
try (OutputStream outputStream = new FileOutputStream("d:/Java/Test/test.txt",true)){
byte[] bytes = {'h','e','l','l','o'};
outputStream.write(bytes);
}catch (IOException e){
e.printStackTrace();
}
}
}

寫之前

寫之后

PrintWriter
這個(gè)類提供了print/println/printf進(jìn)行文件的寫入操作
public class demo13 {
public static void main(String[] args) {
try(PrintWriter writer = new PrintWriter("d:/Java/Test/test.txt")) {
writer.printf("%d + %d = %d" , 10,20,30);
}catch (IOException e){
e.printStackTrace();
}
}
}

Reader和Writer
Reader是一個(gè)抽象類,因此不可以直接實(shí)例化對(duì)象,但是可以實(shí)例化FileReader對(duì)象


public class demo10 {
public static void main(String[] args) {
try(Reader reader = new FileReader("d:/Java/Test/test.txt")) {
while (true){
int n = reader.read();
if(n == -1){
break;
}
// System.out.print(n);
System.out.println((char) n);
}
}catch (IOException e){
e.printStackTrace();
}
}
}

上面這樣重復(fù)讀取,一次讀取一個(gè)字符有些浪費(fèi)時(shí)間,因此這里可以每次使用一個(gè)char[]進(jìn)行接收1024個(gè)字符,就這樣,循環(huán)讀取,直到讀取完
public class demo10 {
public static void main(String[] args) {
try(Reader reader = new FileReader("d:/Java/Test/test.txt")) {
//上面這樣會(huì)重復(fù)讀取,因此我們可以使用一個(gè)char[]數(shù)組一次接收1024個(gè)字符
while (true){
char[] chars = new char[1024];
int n = reader.read(chars);//將讀取到的信息放入chars數(shù)組中
if(n == -1){
break;
}
for (int i = 0; i < n; i++) {
System.out.println(chars[i]);
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}


//Writer是一個(gè)抽象類 Writer writer = new FileWriter()
public class demo11 {
public static void main(String[] args) {
try(Writer writer = new FileWriter("d:/Java/Test/test.txt")){
writer.write("hello world");
}catch (IOException e){
e.printStackTrace();
}
}
}

實(shí)例練習(xí)
示例一
掃描指定?錄,并找到名稱中包含指定字符的所有普通?件(不包含?錄),并且后續(xù)詢問??是否要?jiǎng)h除該?件
1.先輸入目錄和關(guān)鍵字 2.讀取內(nèi)容,獲取路徑,并進(jìn)行刪除
//根據(jù)關(guān)鍵字,當(dāng)前目錄下找出所有相關(guān)的文件
public class demo14 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請(qǐng)輸入你要搜索的根目錄");
String rootPath = sc.next();
File rootfile = new File(rootPath);
if(!rootfile.isDirectory()){
System.out.println("輸入目錄不存在或者不是目錄");
return;
}
System.out.println("請(qǐng)輸入你要找的關(guān)鍵字");
String key = sc.next();
reserch(rootfile,key);
}
//找文件
private static void reserch(File rootfile, String key) {
//列出文件所有內(nèi)容
File[] files = rootfile.listFiles();
if(files == null){
System.out.println("文件目錄下為空");
return;
}
for(File file : files){
//判斷是否是文件
if(file.isFile()){
//判斷是否包含關(guān)鍵字
Delete(file,key);
}else if(file.isDirectory()){
//是目錄文件,需要繼續(xù)搜索
reserch(file,key);
}else{
}
}
}
//刪除操作
private static void Delete(File file, String key) {
Scanner sc = new Scanner(System.in);
//判斷是否包含關(guān)鍵字
if(file.getName().contains(key)){
System.out.println("找到文件"+file.getAbsolutePath());
System.out.println("是否刪除:Y/N");
String choice = sc.next();
//進(jìn)行刪除
if(choice.equals("Y")||choice.equals("y")){
file.delete();
}else{
System.out.println("取消刪除");
}
}
}
}


刪除成功

示例二
進(jìn)?普通?件的復(fù)制
1.輸入源文件路徑和目標(biāo)目錄(判斷是否存在) 2.進(jìn)行源文件讀和目標(biāo)文件的寫(目標(biāo)文件會(huì)自動(dòng)創(chuàng)建,因此目標(biāo)文件只要父目錄存在即可)
//將一個(gè)文件的內(nèi)容復(fù)制到另一個(gè)文件中
public class demo15 {
public static void main(String[] args) {
//1.輸入復(fù)制和被復(fù)制的文件目錄
Scanner sc = new Scanner(System.in);
System.out.println("輸入源文件路徑");
String src = sc.next();
System.out.println("輸入目標(biāo)文件路徑");
String dest = sc.next();
//判斷sc這個(gè)路徑是否合法
File srcFile = new File(src);
if(!srcFile.isFile()){
System.out.println("源文件路徑不合法");
return;
}
//判斷目標(biāo)文件的parent是否存在
File destFile = new File(dest);
if(!destFile.getParentFile().isDirectory()){
System.out.println("目標(biāo)文件不合法");
return;
}
//打開src和dest文件,對(duì)dest進(jìn)行寫入
try(InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(destFile)) {
while (true) {
byte[] bytes = new byte[1024];
int n = inputStream.read(bytes);
if (n == -1) {
break;
}
outputStream.write(bytes, 0, n);
}
}catch (IOException e){
e.printStackTrace();
}
}
}


示例三
掃描指定?錄,并找到名稱或者內(nèi)容中包含指定字符的所有普通?件(不包含?錄)
這里和示例一區(qū)別就是也需要對(duì)文件內(nèi)容進(jìn)行判斷是否包含關(guān)鍵字
public class demo16 {
public static void main(String[] args) {
//1.輸入根目錄和關(guān)鍵字
Scanner sc = new Scanner(System.in);
System.out.println("請(qǐng)輸入根目錄");
String rootPath = sc.next();
System.out.println("請(qǐng)輸入關(guān)鍵字");
String key = sc.next();
//判斷key關(guān)鍵字是否合法
if(key.isEmpty()){
System.out.println("關(guān)鍵字不合法");
return;
}
File rootFile = new File(rootPath);
if(!rootFile.isDirectory()){
//不是路徑
System.out.println("根目錄有誤");
return;
}
search(rootFile,key);
}
public static void search(File rootFile,String key){
//列出所有
File[] files = rootFile.listFiles();
if(files == null){
System.out.println("沒有文件");
return;
}
for(File file : files){
if(file.isFile()){
//進(jìn)行文件名及其內(nèi)容進(jìn)行判斷是否有關(guān)key關(guān)鍵字
trySearch(file,key);
}else if(file.isDirectory()){
//如果是路徑,需要繼續(xù)進(jìn)行找
search(file,key);
}
}
}
private static void trySearch(File file, String key) {
//1.先看文件名是否包含
if(file.getName().contains(key)){
System.out.println("找到了!通過文件名"+file.getAbsolutePath());
}
//這里判斷內(nèi)容中是否有關(guān)于關(guān)鍵字的,此時(shí)文件內(nèi)容放一起進(jìn)行判斷內(nèi)容是否有關(guān)于這個(gè)關(guān)鍵字
//使用Reader這樣可以一個(gè)字符,一個(gè)字符的讀取
try(Reader reader = new FileReader(file)) {
StringBuffer result = new StringBuffer();
while (true){
char[] chars = new char[1024];
int n = reader.read(chars);
if(n == -1){
break;
}
//將真實(shí)字符數(shù)量拼接一起
result.append(chars,0,n);
}
if(result.indexOf(key) >= 0){
//找到了
System.out.println("找到了!內(nèi)容匹配" + file.getAbsolutePath());
}else {
return;
}
}catch (IOException e){
e.printStackTrace();
}
}
}




總結(jié)
到此這篇關(guān)于Java中文件操作和IO實(shí)例練習(xí)的文章就介紹到這了,更多相關(guān)Java文件操作和IO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java 發(fā)送http和https請(qǐng)求的實(shí)例
下面小編就為大家分享一篇java 發(fā)送http和https請(qǐng)求的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01
JavaWeb項(xiàng)目中dll文件動(dòng)態(tài)加載方法解析(詳細(xì)步驟)
這篇文章主要介紹了JavaWeb項(xiàng)目中dll文件動(dòng)態(tài)加載方法,步驟詳細(xì),在這里分享給大家,需要的朋友可以了解下。2017-09-09
五分鐘教你手寫 SpringBoot 本地事務(wù)管理實(shí)現(xiàn)
這篇文章主要介紹了五分鐘教你手寫 SpringBoot 本地事務(wù)管理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Java中List.of()和Arrays.asList()的區(qū)別及原因分析
這篇文章主要介紹了Java中List.of()和Arrays.asList()的區(qū)別及原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java使用定時(shí)器編寫一個(gè)簡(jiǎn)單的搶紅包小游戲
這篇文章主要為大家介紹了Java如何使用定時(shí)器編寫一個(gè)簡(jiǎn)單的搶紅包小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-07-07
五種SpringBoot實(shí)現(xiàn)數(shù)據(jù)加密存儲(chǔ)的方式總結(jié)
這篇文章主要為大家詳細(xì)介紹了五種常見數(shù)據(jù)加密存儲(chǔ)的方法(結(jié)合SpringBoot和MyBatisPlus框架進(jìn)行實(shí)現(xiàn)),文中的示例代碼講解詳細(xì),需要的可以參考下2023-11-11

