13.1.File類的使用
File類的使用
1.File類的一個對象,代表一個文件或一個文件目錄(俗稱: 文件夾)
2.File類聲明在java.io包下
3.File類中涉及到關于文件或文件目錄的創(chuàng)建,刪除,重命名,修改時間,文件大小等方法,
并未涉及到寫入或讀取文件內容的操作.若需要讀取或寫入文件內容,必須用IO流來完成.
4.后續(xù)File類的對象常會作為參數(shù)傳遞到流的構造器中,指明讀取或寫入的"終點"(:從哪讀或寫入到哪,或叫節(jié)點,這個點就用File來表示),真的要讀寫內容了,File類的對象主要指的是一個文件就不是文件目錄了
- File類的實例化
1.如何創(chuàng)建File類的實例
File(String filePath)
File(String filePath, String childPath)
File(File parentFile, String childPath)
2.相對路徑: 相較于某個路徑下,指明的路徑
絕對路徑: 包含盤符在內的文件或文件目錄的路徑
3.路徑分隔符:
windows: \
unix: /
@Test
public void test1(){
// 構造器1
File file1 = new File("hello.txt");// 路徑相對于當前module
File file2 = new File("F:\\markdown\\JavaSE\\基礎語法\\src\\com\\JavaSenior\\IO\\he.txt");// 第二條斜杠表示避免轉義的意思
// 這里還這是單元測試現(xiàn)在還不需要對應硬盤中的文件,此時就僅僅只是內存層面的對象,還沒有涉及到對文件中的數(shù)據(jù)的操作,現(xiàn)在就理解為內存層面對象而已
System.out.println(file1);
System.out.println(file2);
// 構造器2,在上一層目錄下指定的可以是文件也可以是文件目錄
File file3 = new File("F:\\markdown\\JavaSE\\基礎語法\\src\\com","JavaSenior");// 上一層目錄和下一層目錄
System.out.println(file3);
// 構造器3: 在file3的目下創(chuàng)建的文件
File file4 = new File(file3, "hi.txt");
System.out.println(file4);
}
- File類的常用方法
// File類的常用方法
@Test
public void test2(){
File file1 = new File("hello.txt");
File file2 = new File("F:\\markdown\\IO\\hi.txt");
// 獲取絕對路徑
System.out.println(file1.getAbsolutePath());
// 獲取路徑
System.out.println(file1.getPath());
//獲取名字
System.out.println(file1.getName());
// 獲取上層文件目錄路徑,若無返回null
System.out.println(file1.getParent());
// 獲取文件長度(大小)(即:字節(jié)數(shù)).不能獲取目錄長度
System.out.println(file1.length());
// 獲取最后一次修改時間,毫秒值
System.out.println(new Date(file1.lastModified()));
System.out.println();
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());
System.out.println(file2.getName());
System.out.println(file2.getParent());
System.out.println(file2.length());
System.out.println(file2.lastModified());
}
// 如下的兩個方法適用于文件目錄:
//public String[] list(): 獲取指定目錄下的所有文件或文件目錄的名稱數(shù)組
// public File[] listFiles(): 獲取指定模流下的所有文件或文件目錄的File數(shù)組
@Test
public void test3(){
File file = new File("F:\\markdown\\JavaSE");
String[] list = file.list();// 獲取下一層目錄或文件
for (String s : list) {
System.out.println(s);
}
File[] files = file.listFiles();// 以絕對路徑方式獲取下一層文件或目錄
for (File f : files) {
System.out.println(f);
}
}
/*
public boolean renamTo(File dest): 把文件移動到指定文件路徑并重命名
比如: file1.renameTo(file2)為例:
要想保證返回true,要file1在硬盤中是存在的,且file2不能在硬盤中存在
*/
@Test
public void test4(){
File file1 = new File("hello.txt");
File file2 = new File("F:\\markdown\\IO\\hi.txt");
boolean renameTo = file1.renameTo(file2);
System.out.println(renameTo);
}
@Test
public void test5(){
File file1 = new File("hello.txt");
System.out.println(file1.isDirectory());//是否為文件目錄
System.out.println(file1.isFile());// 是否為文件
System.out.println(file1.exists());//是否真正在硬盤中存在
System.out.println(file1.canRead());//是否可讀
System.out.println(file1.canWrite());//是否可寫
System.out.println(file1.isHidden());//是否隱藏
// 判斷文件呢目錄
File file2 = new File("F:\\markdown\\IO");
System.out.println(file2.isDirectory());
System.out.println(file2.isFile());
System.out.println(file2.exists());
System.out.println(file2.canRead());
System.out.println(file2.canWrite());
System.out.println(file2.isHidden());
}
@Test
public void test6() throws IOException {
File file1 = new File("hi.txt");
// 如果不存在
if (!file1.exists()) {
// 創(chuàng)建文件.若文件真實存在硬盤中,則不創(chuàng)建,返回false
file1.createNewFile();
System.out.println("創(chuàng)建成功");
}else{// 文件存在
// 刪除磁盤中的文件或文件目錄,java中的刪除不走回收站
file1.delete();
System.out.println("刪除成功");
}
}
@Test
public void test7(){
// 文件目錄(夾)的創(chuàng)建
File file1 = new File("F:\\markdown\\IO\\IO1\\IO3");// 上一層目錄存在
// 創(chuàng)建文件目錄.如果此文件目錄存在,就不創(chuàng)建了.如果此文件目錄的上層目錄不存在,也不創(chuàng)建
boolean mkdir = file1.mkdir();
if (mkdir) {
System.out.println("創(chuàng)建成功1");
}
File file2 = new File("F:\\markdown\\IO\\IO1\\IO4");
// 創(chuàng)建文件目錄,若上層文件目錄不存在,一并創(chuàng)建
boolean mkdirs = file2.mkdirs();
if (mkdirs) {
System.out.println("創(chuàng)建成功2");
}
// 文件刪除,要想成功,欲刪除的文件目錄下不能有子目錄或文件
File file3 = new File("F:\\markdown\\IO\\IO1\\IO3");
System.out.println(file3.delete());
}
File類的練習
public class FileDemo {
// 在
@Test
public void test1() throws IOException {
// 創(chuàng)建一個與file同目錄下的另一個文件,名為"haha.txt"
File file = new File("F:\\markdown\\IO\\IO1\\hello.txt");
File destFile = new File(file.getParent(), "haha.txt");
boolean newFile = destFile.createNewFile();
if (newFile) {
System.out.println("創(chuàng)建成功");
}
}
// 打印出指定目錄所有文件名稱,包括子文件目錄中的文件
@Test
public void test4(){
// 創(chuàng)建目錄對象
File dir = new File("F:\\markdown\\JavaSE");
printSubFile(dir);
}
public static void printSubFile(File dir){
// 打印目錄子文件
File[] subFiles = dir.listFiles();
// 循環(huán)每個子文件
for (File f : subFiles) {
// 判斷子文件是否文件目錄
// 是文件夾,遞歸打印文件目錄方法
if (f.isDirectory()) {
printSubFile(f);
}else{
// 不是文件夾,輸出每個文件的絕對地址
System.out.println(f.getAbsolutePath());
}
}
}
}
13.2.IO流原理及流的分類
- 字節(jié)流: 以一個byte(8bit)為基本單位傳輸?shù)牧?適合處理非文本數(shù)據(jù)
- 字符流: 以一個char(兩個字節(jié):16bit)為基本單位傳輸?shù)?適合處理文本數(shù)據(jù)
- 節(jié)點流: 直接作用在文件上的流
- 處理流: 作用在已有節(jié)點流處理之上的
- IO流的體系結構
一.流的分類:
1.操作的數(shù)據(jù)單位: 字節(jié)流,字符流
2.數(shù)據(jù)的流向: 輸入流,輸出流
3.流的角色: 節(jié)點流,處理流
二.流的體系結構
抽象基類 | 節(jié)點流(或文件流) | 緩沖流(處理流的一種) |
---|---|---|
InputStream | FileInputStream (read(byte[] buffer)) | BufferedInputStream (read(byte[] buffer)) |
OutputStream | FileOutputStream (write(byte[] buffer,0,len)) | BufferedOutputStream (write(byte[] buffer,0,len))/ flush() |
Reader | FileReader (read(char[] cbuf)) | BufferedReader (read(char[] cbuf)) |
Writer | FileWriter (write(char[] cbuf,0,len)) | BufferedWriter (write(char[] cbuf,0,len))/ flush() |
13.3.節(jié)點流(或文件流).
- FileReader讀入數(shù)據(jù)的基本操作
public class FileReaderWriterTest {
public static void main(String[] args) {
// 用絕對路徑可以無視main和單元測試
// 相較于當前工程: F:\markdown\JavaSE\hello.txt
File file = new File("hello.txt");
System.out.println(file.getAbsolutePath());
File file1 = new File("IO\\hello.txt");// 地址這要寫就可以相較于當前module下
System.out.println(file1.getAbsolutePath());
}
/*
將IOmodule下的hello.txt文件內容讀入程序中,并輸出到控制臺,實現(xiàn)讀取硬盤中文件的操作
說明點:
1.read()的理解: 返回讀入的一個字符.如果達到文件末尾,返回-1
2.異常處理: 為了保證流資源一定可以執(zhí)行關閉操作.要使用try-catch-finally處理
3.讀入的文件一定要存在,否則就會報FileNotFoundException
*/
@Test // 單元測試,歸具體的module所有
public void testFileReader() {
// 異常處理用try-catch比throws好,假如流的對象創(chuàng)建好了沒有拋異常,但是下面read的時候出現(xiàn)阻塞讀不過來拋了一個IOException
// 出現(xiàn)了異常就會創(chuàng)建一個異常對象,默認情況下就拋出程序了,相當于程序后面就不執(zhí)行了,這個時候流就沒關,資源就浪費了,存在內存泄露
// 為了保證即使出現(xiàn)了read異常也要能執(zhí)行流的資源能執(zhí)行關閉操作,所以不要用過throws處理,流資源的關閉放在finally是為了防止中途return退出
FileReader fr = null; // 因為外部要使用,所以這里要先定義
try {
// 1.實例化File類的對象,指明要操作的文件
File file = new File("hello.txt");// 相較于當前module:F:\markdown\JavaSE\基礎語法\hello.txt
// 2.提供具體的字符流來操作文件,相當于給文件提供一個管道來輸出數(shù)據(jù)
fr = new FileReader(file);// 參數(shù)提供文件的路徑或名字,上面的file文件一定要存在,否則就會報異常
// 打開管道的開關,讓數(shù)據(jù)流出
// 3.數(shù)據(jù)的讀入
// read(): 返回讀入的一個字符.如果達到文件末尾,返回-1,讀的是char類型但返回的是字符的int型值
// int data = fr.read();// 讀取文件返回單個字符,文件讀完(讀取字符末尾結束時)返回-1,文件有多個字符就要用到循環(huán)
// 如果文件是空的,上來就是-1,所以先要做判斷,并且有好多字符要讀,用while循環(huán)
/*while (data != -1) {
// 以字符形式輸出每個字符
System.out.print((char) data);
// 再讀一個看看是不是-1
data = fr.read();//像迭代器一樣
}*/
// 方式二: 把方法直接寫到循環(huán)體表達式匯總
int data;
while ((data = fr.read()) != -1) {
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 4.手動關閉流的操作,防止內存泄露
/*try {
// 假如文件流對象沒有實例化出現(xiàn)了異常,這里關閉會出現(xiàn)空指針異常,所以造了對象才要關閉
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}*/
// 或
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- FileReader使用read(char[ ] cbuf)讀入數(shù)據(jù)
// 對read()操作升級: 使用read的重載方法
@Test
public void testFileReader1() {
FileReader fr = null;
try {
// 1.File類的實例化(創(chuàng)建文件)
File file = new File("hello.txt");
// 2.FileReader流的實例化(創(chuàng)建讀取文件的流對象)
fr = new FileReader(file);
// 3.讀入的操作
// read(char[] cubf): 返回每次到底寫入cbuf數(shù)組中的字符的個數(shù).如果達到文件末尾,返回-1
// 先創(chuàng)建一個數(shù)組用來緩存要讀數(shù)據(jù)的個數(shù)
char[] cbuf = new char[5];// 可以存放5個字符的數(shù)組
int len;// 定義每次讀數(shù)據(jù)的個數(shù)
// 判斷每次讀數(shù)據(jù)的個數(shù),并且每讀一次數(shù)據(jù)都會覆蓋一次數(shù)組,可以理解為數(shù)組元素的替換
while ((len = fr.read(cbuf)) != -1) {
// 如果遍歷的長度為cbuf.length,輸出的結果就是123ld,因為最后一次只有3個字符,無法完全覆蓋上一次 最后2個字符就留下了,所以不能是
// 方式一:
// 錯誤的寫法
/*for (int i = 0; i < cbuf.length; i++) {
}*/
// 正確寫法: 每次讀進去幾個就遍歷幾個,不要過多的取后面的
/*for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}*/
// 方式二:
// 錯誤,對應著方式一的錯誤寫法
// 這里cbuf第三次讀取還是保留最后的ld的,相當于數(shù)組有什么就全取出來了,其實跟cbuf.length一樣
/*String str = new String(cbuf);// char型數(shù)組轉成String型數(shù)組
System.out.print(str);*/
// 正確寫法: 用String的重載構造器,從頭開始取,取到第len個
String str = new String(cbuf, 0, len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally { // 寫在finally里防止try的時候return
// 4.資源的關閉
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- FileWriter寫出數(shù)據(jù)的操作
從內存中寫出數(shù)據(jù)到硬盤的文件里
說明:
1.輸出操作,對應的File可以不存在的.
File對應的硬盤中的文件若不存在,在輸出過程中,會自動創(chuàng)建此文件
若存在:
如果流用的構造器是: FileWriter(file,false) / FileWriter(file): 會對原有文件進行覆蓋
如果流用的構造器是: FileWriter(file,true): 不會對原有文件覆蓋, 而是在原有文件基礎上追加內容
@Test
public void testFileWriter() throws IOException {
FileWriter fw = null;
try {
// 1.提供File類的對象,指明寫出的文件
File file = new File("hello1.txt");
// 2.提供FileWriter類(數(shù)據(jù)流)的對象,用于數(shù)據(jù)的寫出
fw = new FileWriter(file, true);// 第二個參數(shù)的意思: 是否在原有文件上添加,表示對原有文件的覆蓋,默認為false
// 3.寫出操作
fw.write("have dream\n");
fw.write("have dream");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 4.流資源關閉
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 用FileReader和FileWriter實現(xiàn)文本文件的復制
@Test
public void testFileReaderFileWriter() {
FileReader fr = null;
FileWriter fw = null;
try {
// 1.創(chuàng)建File類的對象,指明讀取和寫出的文件
// 不能用字符流處理圖片等字節(jié)數(shù)據(jù)
File srcFile = new File("hello.txt");
File destFile = new File("hello2.txt");
// 2.創(chuàng)建輸入流和輸出流的對象
fr = new FileReader(srcFile);// 對于輸入流,文件一定要存在
fw = new FileWriter(destFile);// 文件可以不存在
// 3.讀入內存和寫出硬盤操作
// 一次讀多個先創(chuàng)建一個數(shù)組
char[] cbuf = new char[5];
int len;// 記錄每次讀入到cbuf數(shù)組中字符的個數(shù)
// 循環(huán)讀入: fr流對象讀入到cbuf數(shù)組返回讀入了幾個 如果不是-1就還有數(shù)據(jù)
while ((len = fr.read(cbuf)) != -1) {
// 把數(shù)據(jù)寫出到硬盤當中
// 錯誤:若這樣寫 每次5個5個就把數(shù)據(jù)讀出來了
// fw.write(cbuf);
// 正確: 讀進去幾個就寫出幾個
fw.write(cbuf, 0, len);// 每次從0開始寫出len個字符
// 循環(huán)結束返回-1
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// 4.關閉流資源,建議從下往上關
// 兩個操作并列寫就可以了(也可以用finally),因為就算中途出現(xiàn)異常也已經(jīng)catch掉了,不影響try以外的代碼運行,try里面代碼出現(xiàn)異常,內部接著往下的才不執(zhí)行
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符流不能處理圖片文件的測試
用FileInputStream不能讀取文本文件的測試
用FileInputStream和FileOutputStream讀寫非文本文件
用FileInputStream和FileOutputStream復制文件的測試
13.4.緩沖流
- 緩沖流(字節(jié)型)實現(xiàn)非文本文件的復制
13.5.轉換流
轉換流概述與InputStreamReader的使用
轉換流實現(xiàn)文件的讀入和寫出
13.6.標準輸入輸出流
13.7.打印流
13.8.數(shù)據(jù)流
13.9.對象流
- 對象流序列化與反序列化字符串操作
對象流的使用
1.ObjectInputStream 和 ObjectOutputStream
2.作用:用于存儲和讀取基本數(shù)據(jù)類型數(shù)據(jù)或對象的處理流逼龟。他的強大之處就是可以把Java中的對象寫入到數(shù)據(jù)源中,也能把對象從數(shù)據(jù)源中還原回來
3.要想一個java對象是可序列化的垃它,需要滿足相應的要求。見Person.java
public class ObjectInputOutputStreamTest {
/*
序列化過程:將內存中的java對象保存到磁盤中或通過網(wǎng)絡傳輸出去
使用ObjectOutPutStream輸出實現(xiàn)
*/
@Test
public void testObjectOutputStream(){
ObjectOutputStream oos = null;
try {
// 1.造一個對象處理流包住一個節(jié)點流,造文件和流寫在一起
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
// 2.寫出到磁盤的對象
// 一開始內存當中有個對象就是這個String,隨時可能會被回收,就把他持久化保存起來,
// 或者可以不生成文件,通過網(wǎng)絡把它傳出去也行,傳出去以后再另外一端又可以把它還原成字符串
oos.writeObject(new String("我愛天安門"));
// 顯式的刷新操作
oos.flush();
oos.writeObject(new Person("王敏", 23));// 被持久化到Object.dat文件里
oos.flush();
// 序列化自定義類,該類的屬性也全都要可序列化
oos.writeObject(new Person("張帥", 21,1001,new Account(5000)));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (oos != null) {
// 3.流關閉
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
反序列化過程: 將磁盤文件中的對象還原為內存中的一個java對象,或通過網(wǎng)絡方式獲取到流,把網(wǎng)絡中的流的數(shù)據(jù)還原為java層面的對象
使用ObjectInputStream來實現(xiàn)
*/
@Test
public void testInputStream(){
ObjectInputStream ois = null;
try {
// 1.造文件和流對象
ois = new ObjectInputStream(new FileInputStream("object.dat"));
// 2.寫出磁盤操作,一般寫入的都是同一個類型的
Object obj = ois.readObject();// 通常往里放的都是同類型的對象
String str = (String) obj;// 這個對象其實是個字符串所以可以強轉
Person p = (Person) ois.readObject();
Person p1 = (Person) ois.readObject();
// 還原為內存層面
System.out.println(str);
System.out.println(p);
System.out.println(p1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
// 3.流關閉
try {
if (ois != null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Person類要滿足如下的需求,方可序列化
1.要實現(xiàn)標識接口: Serializable
2.當前類要提供一個全局常量: serialVersionUID(版本序列號)
如果不添加這個全局常量,給這個類的對象序列化了,存儲在磁盤中,緊接著對Person類修改了,修改后,自動生成的serialVersionUID就變了,
變了再去還原的話就找不到當初序列化的全局常量對應的Person,在還原時候就出問題了(報異常)
3.除了當前Person類需要實現(xiàn)Serializable接口之外,還必須保證其內部所有屬性也必須是可序列化的弱判。(默認情況下岔乔,基本數(shù)據(jù)類型是可序列化的)
補充: ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量
static屬于類的資源不歸對象所有所以不能序列化琉苇,transient是瞬態(tài)的
transient:被修飾的成員屬性變量不能被序列化
4.對象序列化機制允許把內存中的Java對象轉換成平臺無關的二進制流匕垫,
從而允許把這種二進制流持久地保存在磁盤上狰腌,或通過網(wǎng)絡將這種二進制流傳輸?shù)搅硪粋€網(wǎng)絡節(jié)點除破。
當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象
public class Person implements Serializable {
public static final long serialVersionUID = 451615182L;
private static String name;
private transient int age;
private int id;
private Account acct;// 自定義類屬性也要是可序列化的,
public Person(String name, int age, int id, Account acct) {
this.name = name;
this.age = age;
this.id = id;
this.acct = acct;
}
public Person(String name, int age, Account acct) {
this.name = name;
this.age = age;
this.acct = acct;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", acct=" + acct +
'}';
}
}
class Account implements Serializable{
// 加上唯一的全局靜態(tài)常量避免反序列化報異常
public static final long serialVersionUID = 4515182L;
private double balance;
public Account(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"balance=" + balance +
'}';
}
}
13.10.隨機存取文件流
RandomAccessFile的使用
1.RandomAccessFile直接繼承于java.Lang.Object類琼腔,實現(xiàn)了DataInput和DataOutput接口
2.RandomAccessFile既可以作為一個輸入流,又可以作為一個輸出流
3.如果RandomAccessFile作為輸出流時,寫出到的文件若不存在,則在執(zhí)行過程中自動創(chuàng)建
若寫出到的文件存在,則會對原有文件內容進行覆蓋.(默認情況下,從頭覆蓋,能覆蓋多少算多少)
4.可以通過把指定指針位置后的內容緩存起來,然后再在指定指針位置插入新值,再把緩存的內容追加回原來的文件,實現(xiàn)RandomAccessFile"插入"數(shù)據(jù)的效果
public class RandomAccessFileTest {
@Test
public void test11() throws FileNotFoundException {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
// 1.造流的對象
raf1 = new RandomAccessFile(new File("pic.jpg"), "r");// 只讀模式
raf2 = new RandomAccessFile(new File("pic3.jpg"), "rw");// 可讀可寫模式
// 2.讀入寫出操作
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
// 3.流關閉
if (raf2 != null) {
raf2.close();
}
if (raf1 != null) {
raf1.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void test2() throws IOException {
// 創(chuàng)建寫出流的對象和文件對象
RandomAccessFile raf1 = new RandomAccessFile("hello4.txt", "rw");
// 寫出操作
raf1.seek(3);// 將指針調到角標為3的位置
raf1.write("xyz".getBytes());// 覆蓋掉原來文件里的頭三個字符
// 流關閉
raf1.close();
}
/*
用RandomAccessFile實現(xiàn)數(shù)據(jù)的插入效果
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello4.txt", "rw");
raf1.seek(3);// 將指針調到下標為3的位置
// 將讀取的數(shù)據(jù)存入一個數(shù)組,將數(shù)組長度先設置為文件長度的大小避免擴容,提高效率,length()返回一個long類型的值
// 保存指針角標3后面的所有數(shù)據(jù)到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello4.txt").length());//新造數(shù)組的大小要么比原文件小,要么和源文件一樣大
// 讀取操作
byte[] buffer = new byte[20];
int len;
while ((len = raf1.read(buffer)) != -1) {
// 把每次遍歷的字符放入builder數(shù)組中
builder.append(new String(buffer, 0, len));
}
// 此時指針自動跑到最后了,將指針調回角標為3的位置
raf1.seek(3);
// 插入"xyz"的數(shù)據(jù),相當于對原有內容進行覆蓋
raf1.write("xyz".getBytes());// 這里write返回byte[]類型,所以要用getBytes()
// 寫出后不用再調指針了,指針已經(jīng)在z的后面了
// 將builder中的數(shù)據(jù)寫入到文件中
raf1.write(builder.toString().getBytes());
// 關閉流
raf1.close();
}
}
13.11.NIO.2中Path,Paths,Files類的使用
- 用第三方jar包實現(xiàn)數(shù)據(jù)讀寫
14.1.網(wǎng)絡編程概述
14.2.網(wǎng)絡通信要素概述
14.3.通信要素1: IP和端口號
- 端口號的理解
public class InetAddressTest {
public static void main(String[] args) {
// 創(chuàng)建一個對象,其對應的ip就是方法的參數(shù)
// 類似于File file = new File("hello.txt");
// 內存中的file對象對應著hello.txt路徑的文件
try {
InetAddress inet1 = InetAddress.getByName("192.168.10.14");// 參數(shù)host代表主機名
System.out.println(inet1);
InetAddress inet2 = InetAddress.getByName("www.taobao.com");
System.out.println(inet2);
InetAddress inet3 = InetAddress.getByName("127.0.0.1");
System.out.println(inet3);
// 直接獲取本地IP地址的方法
InetAddress inet4 = InetAddress.getLocalHost();
System.out.println(inet4);
// getHostName(): 獲取域名
System.out.println(inet2.getHostName());
// getHostAddress(): 獲取主機地址
System.out.println(inet2.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
14.4.通信要素2: 網(wǎng)絡協(xié)議
- TCP和UDP網(wǎng)絡通信協(xié)議的對比
- 三次握手: 應該這樣理解:1.A發(fā)送請求 2.B告訴A已經(jīng)收到請求(ACK確認)3.A確認B收到了A的請求 4.A開始數(shù)據(jù)傳輸
14.5.TCP網(wǎng)絡編程
- TCP網(wǎng)絡編程例題:
14.6.udp網(wǎng)絡編程
- UDP編程舉例