文件操作 和 IO

目錄

?編輯一、認識文件

1、文件路徑

2、其它知識

二、Java 中操作文件

三、文件內容的讀寫

1、Reader

2、InputStream

3、輸出


一、認識文件

?文件是在硬盤上存儲數據的一種方式,操作系統幫我們把硬盤的一些細節都封裝起來了

我們只需要了解文件相關的一些接口即可

硬盤是用來存儲數據,和內存相比,硬盤的存儲空間更大,訪問速度更慢,成本更低,可以持久化存儲

操作系統通過 “文件系統” 這樣的模塊來管理硬盤

實際上我的電腦只有一個硬盤,操作系統可以通過文件系統把這個硬盤抽象成多個硬盤一樣?NTFS 是windows 上的文件系統,背后有一定的格式來組織硬盤數據

?EXT4 是 Linux 上常見的文件系統


1、文件路徑

不同的文件系統,管理文件的方式都是類似的

通過 目錄 - 文件 構成了 “ N 叉樹” 樹形結構

通過 D盤 - tmp - cat.jpg 這個路線,就能 找到 / 確定 電腦上的唯一一個文件,這個東西就稱為 “路徑”

在 windows 上,使用 / 或者 \ 來分割不同的目錄

以盤符開頭的路徑,也叫做 “絕對路徑”

絕對路徑相當于與是從 “此電腦” 這里出發,找文件的過程

以 .?或者 ... 開頭的目鏡,叫做 “絕對路徑”

相對路徑,需要有一個 “基準目錄” / “工作目錄”,表示從這個基準出發,怎么走能找到這個文件夾

如果以 D:為基準目錄 ./tmp/cat.jpg? 如果以 D:tmp 為基準 ./cat.jpg (. 表示當前所在目錄)

如果以 D:/tmp/111 為基準, ..cat.jpg(..表示當前目錄的上一級目錄)

同樣是一個 cat.jpg 文件,站在不同的基準目錄上找到的路徑是不一樣的


2、其它知識

文件系統上存儲的文件,又可以分成兩個大類

1、文本文件

存儲的是字符

例如:utf-8 就是一個大表,這個表上的數據的組合,就可以稱為字符

2、二進制文件

存儲的是二進制的數據

如何判斷文件是文本文件還是二進制文件?

一個最簡單的方式:直接使用記事本打開

記事本打開文件,就是嘗試把當前的數據,在碼表中查詢

如果打開之后能看懂,就是文本文件,如果打開之后看不懂,就是二進制文件


二、Java 中操作文件

后續針對文件的操作,文本和二進制的操作方式是不同的

文件系統操作:創建文件,刪除文件,創建目錄....

java 中,不要通過 java.io.file 類來對一個文件(包括目錄)進行具體的描述

IO : input 和 output,我們是站在 cpu 的視角來看待輸入輸出的

通過 File 對象來描述到一個具體的文件

File 對象可以對應到一個真實存在的文件,也可以對應到一個不存在的文件

構造方法:

第二個構造方法此處的字符串,就表示一個路徑,可以是絕對路徑,也可以是相對路徑

方法:?

站在操作系統的角度來看待:目錄也是文件

操作系統的文件是一個更廣義的概念,具體來說有很多不同的類型

1、普通文件(通常見到的文件)

2、目錄文件(通常見到的文件夾)

windows 上,目錄之間的分隔符,可以使用 / 也可以使用 \?

Linux 和 mac 上面,就只支持 /

所以即使在 windows 上,也盡量使用 / ,使用 、 在代碼中需要搭配轉義字符

可以通過代碼,來感受一下對文件的操作:?當我們把絕對路徑改成相對路徑,代碼運行結果又會有所不同:

?getAbsolutePath 會將工作目錄拼接上當前目錄,就是運行的結果

在 idea 中運行一個程序,工作目錄就是項目所在的目錄,在命令行中 運行一個程序,工作目錄就是命令行當前所在的目錄,如果程序是運行在 tomacat 中,工作目錄就是 tomcat 下的 bin 目錄

這個操作是可能會拋出異常的

比如,當前寫入的路徑是一個非法的路徑

比如,當前創建的這個文件,對于所在的目錄沒有權限操作

有的時候,可能會用到這樣的一個功能:臨時文件

程序運行的時候,搞一個臨時文件,程序結束了,臨時文件中自動刪掉

像 office 等很多這樣的生產力軟件 都有產生臨時文件功能,這個臨時文件就自動保存了你當前的編輯的中間狀態

有的人使用 word 不喜歡保存,用了一段時間之后,電腦突然斷電關機了,沒保存的數據難道就沒了嗎?

重啟電腦,由于剛才是非正常關閉,臨時文件是來不及刪除,仍然存在的moffice 啟動就能知道上次是異常關閉了,就會提示你是否要從之前的臨時文件恢復未保存的數據?

?創建目錄代碼:

import java.io.File;
import java.io.FileReader;public class Demo4 {public static void main(String[] args) {File file = new File("./test-dir");//mk -> make dir->directory//mkdir 一次只能創建一層目錄,mkdirs 可以一次創建多層目錄file.mkdir();//file.mkdirs();}
}

?文件重命名也可以起到文件移動的效果

import java.io.File;//文件重命名
public class Demo5 {public static void main(String[] args) {File file = new File("./test.txt");File file2 = new File("./src/test2.txt");file.renameTo(file2);}
}

以上文件系統的操作,都是基于 File 類來完成的

另外還需要文件內容的操作


三、文件內容的讀寫

1、Reader

文件這里的內容本質是來自于硬盤,硬盤又是操作系統管理的,使用某個編程語言操作文件,本質上都是需要調用系統的 api?

雖然不同的編程語言操作文件的 api 有所差別,但是基本步驟都是一樣的

文件內容操作的核心步驟有四個:

1、打開文件

2、關閉文件

3、讀文件

4、寫文件

Java IO流 是一個比較龐大的體系,涉及到非常多的類,這些不同的類,都有各自不同的特性,但是總的來說,使用的方法都是類似的

(1)構造方法,打開文件

(2)close 方法,關閉文件

(3)如果衍生自 InputStream 或者 Read ,就可以使用 read 方法來讀數據

(4)如果衍生自 OutputStream 或者 Writer ,就可以使用 write 方法來寫數據

?讀文件操作:

?這個操作非常重要,釋放必要的資源

讓一個進程打開一個文件,是要從系統這里申請一定的資源的(占用進程的 pcb 的文件描述符表中的一個表項)

如果不釋放,就會出現 “文件資源泄露” ,是一個很嚴重的問題

文件描述符表 可以理解成一個順序表,長度有限,不會自動擴容,一旦一直打開文件,而不去關閉不用的文件,文件描述符表就會被占滿,后續就沒法打開新的文件了

我們可以使用 try with rewsourses 來避免出現上述問題

此時只要 try 代碼執行完畢了,就會自動調用到 close 方法

文件流中的任意對象,都可以按照上述討論來進行 close

一次讀一個 char 類型的數組

?會把讀到的內容,填充到參數的這個 cbuf 數組中,此處的參數,相當于是一個輸出形參數

通過 read ,就會把本來是空的一個數組,填充上內容

n 表示實際讀到的字符的個數

相當于給了 1024 這么大空間,如果文件足夠大,超過 1024,就能填滿這個空間

如果文件比較小,不足1024,就會把文件所有內容都填到數組中(剩下會空余)

返回值 n 就表示實際讀到的字符的個數

有時候,可能會涉及到有多個小文件,都需要讀取并且拼接到一起,就可以使用這個方法

假設現在有三個文件,每個文件的大小是 100 字節

?最終代碼如下:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;//Reader 的使用
public class Demo6 {public static void main(String[] args) throws IOException {
/*        //FileReder 的構造方法,可以填寫一個路徑(絕對路徑和相對路徑都可以),也可以寫一個構造好了的 file 對象Reader reader = new FileReader("d:/test.txt");try {//中間的代碼無論出現什么情況,close 都可以執行到}finally {//如果拋出異常或者 return ,close就都執行不到了reader.close();}*///上述使用 finally 的方式能解決問題,但是不優雅//使用 try with resourses 是更好的解決方法try(Reader reader = new FileReader("d:/test.txt")){while(true){char buf[] = new char[1024];int n = reader.read(buf);if(n == -1){//讀到文件末尾了break;}for(int i = 0;i < n;i++){System.out.print(buf[i] + " ");}}}}
}

2、InputStream

InputStream 是字節流,用法和 Reader 相似

文本文件,也可以使用字節流打開,只不過此時你讀到的每個字節,就不是完整的字符了

?一次讀一個字節

?一次讀若干個字節,嘗試填滿這個 byte[]

一次讀若干個字節,填滿數組的一部分

Java 雖然有 char ,但是很少會用,更多的是使用 String?

此處,我們可以借助一些額外的工具類,就可以完成 字節 / 字符 --> 字符串 的轉化

雖然也可以直接使用 String 的構造方法完成 char[] 或者 byte[] 到字符串的轉化,但是比較麻煩

這個工具類就是 Scanner !!!

操作系統中,所謂的文件,是一個廣義的概念,System.in 是一個特殊的文件,對應到 “標準輸入”,普通的硬盤上的文件,也是文件

后來網絡編程中的網卡(socket),也是文件

Scanner 都是一視同仁的,只是把當前讀到的字節數據進行轉換,但并不關心這個數據是來自于哪里

但是,要注意,Scanner 只是用來讀取文本文件的,不是適合讀取二進制文件

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;public class Demo8 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("d:/test.txt")){Scanner scanner = new Scanner(inputStream);//此時就是從 test.txt 這個文件中讀取數據了String s = scanner.next();System.out.println(s);}}
}

3、輸出

輸出的使用方法和輸入非常相似,關鍵操作是 write?

write 之前要打開文件,write 之后也需要關閉文件

輸出流對象(無論是字節流還是字符流),會在打開文件之后,清空文件內容!!!

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;public class Demo8 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("d:/test.txt")){Scanner scanner = new Scanner(inputStream);//此時就是從 test.txt 這個文件中讀取數據了String s = scanner.next();System.out.println(s);}}
}

還可以按照追加寫的方式打開,此時就不會清空內容了?

讀操作和寫操作,也都能支持隨機訪問,可以移動光標到指定位置進行讀寫,此處就不進行介紹了

OutputStream 方式使用方法完全一樣

只不過 write 方法,不能支持 字符串 參數,只能按照 字節 或者 字節數組來寫入


實例:掃描指定目錄,并找到名稱中包含指定字符的所有普通文件(不包含目錄),并且后續詢問用戶是否要刪除此文件

import java.io.File;
import java.util.Scanner;public class Demo10 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);//1、用戶輸入一個目錄,后續的查找都是針對這個目錄進行的System.out.println("請輸入要搜索的目錄");File rootPath = new File(scanner.next());//2、再讓用戶輸入要搜索和刪除的關鍵粗System.out.println("請輸入要刪除的關鍵字");String word = scanner.next();//3、判斷當前目錄是否有效if (!rootPath.isDirectory()){System.out.println("此時輸入的路徑不是合法目錄");return;}//4、遍歷目錄,從根目錄出發,按照深度優先(遞歸) 的方式進行scanDir(rootPath,word);}public static void scanDir(File currentDir,String word){//1、先列出當前目錄中包含哪些內容File[] files = currentDir.listFiles();if (files == null || files.length == 0){//空的目錄或者非法的目錄return;}//2、遍歷列出的文件,分兩個情況進行討論for(File f : files){if (f.isFile()){//如果當前文件是普通文件,看看文件名是否包含了 word ,來決定是否要刪除dealFile(f,word);}else {//如果當前文件是目錄文件,就遞歸執行 scanDirscanDir(f,word);}}}public static void dealFile(File f,String word){Scanner scanner = new Scanner(System.in);//1、先判斷當前文件是否包含 wordif (!f.getName().contains(word)){//此時文件不包含 word,return;}//2、包含 word,詢問用戶是否刪除該文件System.out.println("該文件是: " + f.getAbsolutePath() + ",是否確認刪除(Y / N )");String choice = scanner.next();if (choice.equals("Y") || choice.equals("y")){f.delete();}}
}

示例:進行普通的文件復制

import java.io.*;
import java.util.Scanner;public class Demo11 {public static void main(String[] args) throws IOException {System.out.println("請輸入要復制的文件路徑");Scanner scanner = new Scanner(System.in);String src = scanner.next();File srcfile= new File(src);if (!srcfile.isFile()){System.out.println("您輸入的源文件路徑是非法的");return;}System.out.println("請輸入要復制到的目標路徑");String dest = scanner.next();File destfile= new File(dest);//不要求目標文件存在,但是得保證目標文件所在的目錄是存在的if (!destfile.getParentFile().isDirectory()){System.out.println("您輸入的目標文件路徑是非法的");return;}//2、進行復制操作的過程,按照字節流打開try(InputStream inputStream = new FileInputStream(srcfile);OutputStream outputStream = new FileOutputStream(destfile)){while(true){byte[] buffer = new byte[1024];int n = inputStream.read(buffer);if (n == -1){System.out.println("讀取到 eof,循環結束");break;}outputStream.write(buffer,0,n);}}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/38623.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38623.shtml
英文地址,請注明出處:http://en.pswp.cn/news/38623.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【前端 | CSS】滾動到底部加載,滾動監聽、懶加載

背景 在日常開發過程中&#xff0c;我們會遇到圖片懶加載的功能&#xff0c;基本原理是&#xff0c;滾動條滾動到底部后再次獲取數據進行渲染。 那怎么判斷滾動條是否滾動到底部呢&#xff1f;滾動條滾動到底部觸發時間的時機和方法又該怎樣定義&#xff1f; 針對以上問題我…

數據集成革新:去中心化微服務集群的無限潛能

在當今數據密集型的業務環境下&#xff0c;傳統的集中式架構已經難以滿足高可用性和高并發性的要求。而去中心化微服務集群則通過分散式的架構&#xff0c;將系統劃分為多個小型的、獨立部署的微服務單元&#xff0c;每個微服務負責特定的業務功能&#xff0c;實現了系統的高度…

centos系統kubeadm安裝K8S_v1.27.x容器使用docker(K8S_v1.24版本以后依然使用docker容器管理)

kubeadm安裝K8S_v1.27.x容器使用docker 按照需要的文檔點擊這里下載 一.環境部署 1.1基礎環境配置 主機IP 主機名規劃 192.168.186.128 k8s-master01 192.168.186.129 k8s-node01 192.168.186.130 k8s-node02 1.2修改機器名稱 #永久修改主機名 hostnamectl set-hostname …

docker搭建opengrok環境

引言&#xff1a; 由于這幾天開始 http://aospxref.com/ 網站沒法用了。用習慣了opengrok的方式看AOSP的源碼&#xff0c;其他的在線查看源碼的網站用起來都不是很理想。所以考慮搭建一個環境。 首先網上看了下opengrok的環境搭建的方式&#xff0c;最終還是采用docker的方…

【JS 一個數組隨機選取x個元素】

可以使用Math.random()方法&#xff0c;結合循環和splice()方法來實現&#xff1a; let arr [1,2,3,4,5,6,7,8,9]; let randomArr [];for(let i 0; i < 4; i) {let randomIndex Math.floor(Math.random() * arr.length);let randomNum arr.splice(randomIndex, 1)[0];…

基于C#的無邊框窗體陰影繪制方案 - 開源研究系列文章

今天介紹無邊框窗體陰影繪制的內容。 上次有介紹使用雙窗體的方法來顯示陰影&#xff0c;這次介紹使用API函數來進行繪制。這里使用的是Windows API函數&#xff0c;操作系統的窗體也是用的這個來進行的繪制。 1、 項目目錄&#xff1b; 下面是項目目錄&#xff1b; 2、 函數介…

日常BUG——SpringBoot模糊映射

&#x1f61c;作 者&#xff1a;是江迪呀??本文關鍵詞&#xff1a;日常BUG、BUG、問題分析??每日 一言 &#xff1a;存在錯誤說明你在進步&#xff01; 一、問題描述 SpringBoot在啟動時報出如下錯誤&#xff1a; Caused by: java.lang.IllegalStateExceptio…

ARM處理器

1、RISC處理器&#xff1a; RISC (Reduced Instruction Set Computer) 微處理器是一種計算機微處理器架構&#xff0c;其設計原則是通過簡化指令集來提高執行速度。 (1)、RISC處理器的設計理念&#xff1a; 簡化指令集&#xff1a;RISC 微處理器的指令集非常精簡&#xff0c…

【Python COM】Word 自動縱向合并相同內容單元格

使用場景 docxtempl 庫不支持動態縱向合并單元格&#xff0c;所以寫了這段代碼用來曲線救國。 使用方法 需要縱向合并的單元格加上在文本末尾加上“【縱向合并】”&#xff0c;然后調用此函數&#xff0c;就會自動縱向合并相同內容的單元格。 代碼 需要安裝 pywin32 庫。 …

VC2015,C++內存中運行EXE文件

VC2015,C內存中運行EXE文件&#xff0c;點擊可以下載 VC2015項目中所用的源碼主要源自于網絡&#xff0c;修正一些錯誤后&#xff0c;源碼如下&#xff0c;此源碼在VC6中可以正常編譯&#xff0c; 但在VC2015中&#xff0c;就會出現一些錯誤&#xff0c;本項目源碼已經把錯誤修…

文件批量重命名001到100

文件批量重命名001到100如何搞定&#xff1f;這是一個許多朋友都在熱議的話題&#xff0c;今天我將向大家介紹這方面的內容&#xff0c;希望你會喜歡。總的來說&#xff0c;文件重命名快捷鍵CtrlF2在日常工作中非常實用。它可以輕松快速地完成文件和文件夾的重命名操作&#xf…

儲能pcb的布局注意事項與制造難點

隨著新能源需求的不斷增長和能源結構的轉型&#xff0c;儲能技術的市場規模不斷擴大。儲能PCB作為儲能系統中電池模塊的重要組成部分&#xff0c;對整個系統的安全性和性能起到關鍵作用。今天我們就來聊聊&#xff0c;儲能pcb有什么特征。 什么是儲能&#xff1a;儲能是指能量…

用友Java后端筆試2023-8-5

計算被直線劃分區域 在笛卡爾坐標系&#xff0c;存在區域[A,B],被不同線劃分成多塊小的區域&#xff0c;簡單起見&#xff0c;假設這些不同線都直線并且不存在三條直線相交于一點的情況。 img 那么&#xff0c;如何快速計算某個時刻&#xff0c;在 X 坐標軸上[ A&#xff0c;…

kubernetes 中的事件(event)簡介以及如何收集event和基于event告警

引用另外一篇文章對k8s event的介紹 1.什么是kubernetes事件 Kubernetes Events 是一種 Kubernetes 資源對象&#xff0c;記錄了某個組件在某個時間做了某個動作&#xff0c;用于展示集群內發生的情況&#xff0c;當 Kubernetes 集群中資源狀態發生變化時&#xff0c;可以產生…

PostMan 教程

安裝https://www.cnblogs.com/mafly/p/postman.html Postman 使用方法詳解https://blog.csdn.net/fxbin123/article/details/80428216 postman進行http接口測試https://blog.csdn.net/five3/article/details/53021084 postman的使用方法詳解&#xff01;最全面的教程https:/…

Golang項目中如何輕松實現私有倉庫pkg包的引入

在企業內部創建一個公共的Golang模塊工程可以幫助提高代碼復用性和開發效率。本文將從如何創建一個公共的Golang工程開始&#xff0c;指導你一步步創建它、并引入到你的工程中。 1、公共模塊規范 下面是一個簡單的步驟指南來創建這樣一個公共模塊項目。 創建版本控制倉庫&am…

Verdi_traceX and autotrace

Verdi_traceX and autotrace Trace X From nWave/nTrace of from the Teporal Flow View. Show Paths on Flow ViewShow Paths on nWave 若Waveform中有X態&#xff0c;鼠標右鍵會有Trace X的選項&#xff1b; 會自動打開Temporal Flow View窗口&#xff0c;展示對應路徑&am…

RocketMQ、Dashboard部署以及安全設置

RocketMQ、dashboard部署以及安全設置 一、啟動RocketMQ1.1 下載RocketMQ1.2 修改配置文件1.2.1 修改nameServer Jvm內存配置1.2.2 修改broker參數 1.3 啟動1.3.1 啟動NameServer1.3.2 啟動Broker1.3.3 測試是否啟動成功1.3.3.1 測試消息發送1.3.3.2 測試消息接收1.3.3.3 Java程…

數據結構——配對堆

引入 配對堆是一個支持插入&#xff0c;查詢/刪除最小值&#xff0c;合并&#xff0c;修改元素等操作的數據結構&#xff0c;是一種可并堆。有速度快和結構簡單的優勢&#xff0c;但由于其為基于勢能分析的均攤復雜度&#xff0c;無法可持久化。 定義 配對堆是一棵滿足堆性質…

C語言暑假刷題沖刺篇——day1

目錄 一、選擇題 二、編程題 &#x1f388;個人主頁&#xff1a;庫庫的里昂 &#x1f390;CSDN新晉作者 &#x1f389;歡迎 &#x1f44d;點贊?評論?收藏?收錄專欄&#xff1a;C語言每日一練 ?其他專欄&#xff1a;代碼小游戲C語言初階&#x1f91d;希望作者的文章能對你…