Java IO流 文件傳輸基礎
一、文件的編碼
package com.study.io; /** * 測試文件編碼 */ public class EncodeDemo { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { String s="好好學習ABC"; byte[] bytes1=s.getBytes();//這是把字符串轉(zhuǎn)換成字符數(shù)組,轉(zhuǎn)換成的字節(jié)序列用的是項目默認的編碼(這里為UTF-8) for (byte b : bytes1) { //把字節(jié)(轉(zhuǎn)換成了int)以16進制的方式顯示 System.out.print(Integer.toHexString(b & 0xff)+" ");//& 0xff是為了把前面的24個0去掉只留下后八位 } System.out.println(); /*utf-8編碼中中文占用3個字節(jié),英文占用1個字節(jié)*/ byte[] bytes2 = s.getBytes("utf-8");//這里會有異常展示,我們就throw這個異常 for (byte b : bytes2) { System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /*gbk編碼中文占用2個字節(jié),英文占用1個字節(jié)*/ byte[] bytes3 = s.getBytes("gbk");//這里會有異常展示,我們就throw這個異常 for (byte b : bytes3) { System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /*utf-16be編碼中文占用2個字節(jié),英文占用2個字節(jié)*/ byte[] bytes4 = s.getBytes("utf-16be");//這里會有異常展示,我們就throw這個異常 for (byte b : bytes4) { System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /*當你的字節(jié)序列是某種編碼時,這個時候想把字節(jié)序列變成字符串,也需要用這種編碼方式,否則會出現(xiàn)亂碼*/ String str1=new String(bytes4);//這時會使用項目默認的編碼來轉(zhuǎn)換,可能出現(xiàn)亂碼 System.out.println(str1); //要使用字節(jié)序列的編碼來進行轉(zhuǎn)換 String str2=new String(bytes4,"utf-16be"); System.out.println(str2); } }
分析:
* 1. “& 0xff”的解釋:
* 0xFF表示的是16進制(十進制是255),表示為二進制就是“11111111”。
* 那么&符表示的是按位數(shù)進行與(同為1的時候返回1,否則返回0)
* 2.字節(jié)byte與int類型轉(zhuǎn)換:
* Integer.toHexString(b & 0xff)這里先把byte類型的b和0xff進行了運算,然后Integer.toHexString取得了十六進制字符串
* 可以看出b & 0xFF運算后得出的仍然是個int,那么為何要和 0xFF進行與運算呢?直接 Integer.toHexString(b);,將byte強轉(zhuǎn)為int不行嗎?答案是不行的.
* 其原因在于:1.byte的大小為8bits而int的大小為32bits;2.java的二進制采用的是補碼形式
* Integer.toHexString的參數(shù)是int,如果不進行&0xff,那么當一個byte會轉(zhuǎn)換成int時,由于int是32位,而byte只有8位這時會進行補位。。。。。。
* 所以,一個byte跟0xff相與會先將那個byte轉(zhuǎn)化成整形運算,這樣,結(jié)果中的高的24個比特就總會被清0,于是結(jié)果總是我們想要的。
* 3.utf-8編碼:中文占用3個字節(jié),英文占用1個字節(jié)
* gbk編碼:中文占用2個字節(jié),英文占用1個字節(jié)
* Java采用雙字節(jié)編碼(就是Java中的一個字符占兩個字節(jié))是utf-16be編碼。中文占用2個字節(jié),英文占用2個字節(jié)
*
* 4.當你的字節(jié)序列是某種編碼時,這個時候想把字節(jié)序列變成字符串,也需要用這種編碼方式,否則會出現(xiàn)亂碼
* 5.文本文件 就是字節(jié)序列??梢允侨我饩幋a的字節(jié)序列。
* 如果我們在中文機器上直接創(chuàng)建文本文件,那么該文件只認識ANSI編碼(例如直接在電腦中創(chuàng)建文本文件)
二、File類的使用
package com.study.io; import java.io.File; /** * File類的使用 */ public class FileDemo { /*java.iO.File類表示文件或目錄 File類只用于表示文件或目錄的信息(名稱,大小等),不能用于文件內(nèi)容的訪問。*/ public static void main(String[] args) { File file=new File("D:\\111");//創(chuàng)建文件對象時指定目錄需要用雙斜杠,因為“\”是轉(zhuǎn)義字符 /*目錄的中間的分隔符可以用雙斜杠,也可以用反斜杠,也可以用File.separator設置分隔符*/ // File file1=new File("d:"+File.separator); // System.out.println(file.exists());//exists()判斷文件或文件夾是否存在 if(!file.exists()){//如果文件不存在 file.mkdir();//創(chuàng)建文件夾mkdir(),還有mkdirs()創(chuàng)建多級目錄 }else{ file.delete();//刪除文件或文件夾 } //判斷是否是一個目錄isDirectory,如果是目錄返回true,如果不是目錄或者目錄不存在返回false System.out.println(file.isDirectory()); //判斷是否是一個文件isFile System.out.println(file.isFile()); File file2=new File("D:\\222","123.txt"); //常用API: System.out.println(file);//打印的是file.toString()的內(nèi)容 System.out.println(file.getAbsolutePath());//獲取絕對路徑 System.out.println(file.getName());//獲取文件名稱 System.out.println(file2.getName()); System.out.println(file.getParent());//獲取父級絕對路徑 System.out.println(file2.getParentFile().getAbsolutePath()); } }
運行結(jié)果:
說明:
java.iO.File類表示文件或目錄
File類只用于表示文件或目錄的信息(名稱,大小等),不能用于文件內(nèi)容的訪問。
常用的API:
1.創(chuàng)建File對象:File file=new File(String path);注意:File.seperater();獲取系統(tǒng)分隔符,如:“\”.
2.boolean file.exists();是否存在.
3.file.mkdir();或者file.mkdirs();創(chuàng)建目錄或多級目錄。
4.file.isDirectory()判斷是否是目錄
file.isFile()判斷是否是文件。
5.file.delete();刪除文件或目錄。
6.file.createNewFile();創(chuàng)建新文件。
7.file.getName()獲取文件名稱或目錄絕對路徑。
8.file.getAbsolutePath()獲取絕對路徑。
9.file.getParent();獲取父級絕對路徑。
1、遍歷目錄
package com.study.io; import java.io.File; import java.io.IOException; /** * File工具類 * 列出File類的常用操作,比如:過濾、遍歷等操作 */ public class FileUtils { /** * 列出指定目錄下(包括其子目錄)的所有文件 * @param dir * @throws IOException */ public static void listDirectory(File dir) throws IOException{ if(!dir.exists()){//exists()方法用于判斷文件或目錄是否存在 throw new IllegalArgumentException("目錄:"+dir+"不存在"); } if(!dir.isDirectory()){//isDirectory()方法用于判斷File類的對象是否是目錄 throw new IllegalArgumentException(dir+"不是目錄"); } /*String[] fileNames = dir.list();//list()方法用于列出當前目錄下的子目錄和文件(直接是子目錄的名稱,不包含子目錄下的內(nèi)容),返回的是字符串數(shù)組 for (String string : fileNames) { System.out.println(string); }*/ //如果要遍歷子目錄下的內(nèi)容就需要構(gòu)造成File對象做遞歸操作,F(xiàn)ile提供了直接返回File對象的API File[] listFiles = dir.listFiles();//返回的是直接子目錄(文件)的抽象 if(listFiles !=null && listFiles.length >0){ for (File file : listFiles) { /*System.out.println(file);*/ if(file.isDirectory()){ //遞歸 listDirectory(file); }else{ System.out.println(file); } } } } }
測試類:
public class FileUtilsTest { public static void main(String[] args) throws IOException { FileUtils.listDirectory(new File("D:\\ioStudy")); } }
運行結(jié)果:
三、RandomAccessFile類的使用
RandomAccessFile:java提供的對文件內(nèi)容的訪問,既可以讀文件,也可以寫文件。
RandomAccessFile支持隨機訪問文件,可以訪問文件的任意位置。
注意 Java文件的模型:
運行結(jié)果:
1
12
[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
7f
ff
ff
ff
7f
ff
ff
ff
d6
d0
四、字節(jié)流(FileInputStream、FileOutputStream)
IO流可分為輸入流和輸出流。
這里又可分為字節(jié)流和字符流。
代碼示例:
package com.study.io; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * IO工具類 * ❤文件輸入輸出流: * FileInputStream-->具體實現(xiàn)了在文件上讀取數(shù)據(jù) * FileOutputStream-->實現(xiàn)了向文件中寫出byte數(shù)據(jù)的方法 * ❤數(shù)據(jù)輸入輸出流: * DataOutputStream / DataInputStream:對"流"功能的擴展,可以更加方面的讀取int,long,字符等類型數(shù)據(jù) * DataOutputStream writeInt()/writeDouble()/writeUTF() * ❤字節(jié)緩沖流: * BufferedInputStream & BufferedOutputStream * 這兩個流類位IO提供了帶緩沖區(qū)的操作,一般打開文件進行寫入或讀取操作時,都會加上緩沖,這種流模式提高了IO的性能 * 比如:從應用程序中把輸入放入文件,相當于將一缸水倒入到另一個缸中: FileOutputStream--->write()方法相當于一滴一滴地把水“轉(zhuǎn)移”過去 DataOutputStream-->writeXxx()方法會方便一些,相當于一瓢一瓢把水“轉(zhuǎn)移”過去 BufferedOutputStream--->write方法更方便,相當于一瓢一瓢先放入桶中(即緩存區(qū)),再從桶中倒入到另一個缸中,性能提高了 */ public class IOUtil { /** * 讀取指定文件內(nèi)容,按照16進制輸出到控制臺 * 并且每輸出10個byte換行 * @param fileName * 單字節(jié)讀取不適合大文件,大文件效率很低 */ public static void printHex(String fileName)throws IOException{ //把文件作為字節(jié)流進行都操作 FileInputStream in=new FileInputStream(fileName); int b; int i=1; while((b=in.read())!=-1){ /* 0xff換成2進制就是8個1,這樣與的話,其實就是取到了字符的低8位。 * oxf就是15, 小于15的數(shù)會轉(zhuǎn)換成一個16進制數(shù), * 你的代碼里希望是固定的兩個16進制數(shù),所以當只會產(chǎn)生一個時要加個0*/ if(b <= 0xf){ //單位數(shù)前面補0 System.out.print("0"); } //Integer.toHexString(b)將整型b轉(zhuǎn)換為16進制表示的字符串 System.out.print(Integer.toHexString(b)+" "); if(i++%10==0){ System.out.println(); } } in.close();//文件讀寫完成以后一定要關閉 } /** * 批量讀取,對大文件而言效率高,也是我們最常用的讀文件的方式 * @param fileName * @throws IOException */ public static void printHexByByteArray(String fileName)throws IOException{ FileInputStream in = new FileInputStream(fileName); byte[] buf = new byte[8 * 1024]; /*從in中批量讀取字節(jié),放入到buf這個字節(jié)數(shù)組中, * 從第0個位置開始放,最多放buf.length個 * 返回的是讀到的字節(jié)的個數(shù) */ /*int bytes = in.read(buf,0,buf.length);//一次性讀完,說明字節(jié)數(shù)組足夠大 int j = 1; for(int i = 0; i < bytes;i++){ System.out.print(Integer.toHexString(buf[i] & 0xff)+" "); if(j++%10==0){ System.out.println(); } }*/ int bytes = 0; int j = 1; while((bytes = in.read(buf,0,buf.length))!=-1){ for(int i = 0 ; i < bytes;i++){ System.out.print(Integer.toHexString(buf[i] & 0xff)+" "); /** * & 0xff:byte類型8位,int類型32位,為了避免數(shù)據(jù)轉(zhuǎn)換錯誤,通過&0xff將高24位清零 */ if(j++%10==0){ System.out.println(); } } } in.close(); } /** * 文件拷貝,字節(jié)批量讀取 * @param srcFile * @param destFile * @throws IOException */ public static void copyFile(File srcFile, File destFile) throws IOException { if (!srcFile.exists()) { throw new IllegalArgumentException("文件:" + srcFile + "不存在"); } if (!srcFile.isFile()) { throw new IllegalArgumentException(srcFile + "不是文件"); } FileInputStream in = new FileInputStream(srcFile); FileOutputStream out = new FileOutputStream(destFile);//文件不存在時,會直接創(chuàng)建;如果存在,刪除后建 byte[] buf = new byte[8 * 1024];//批量讀寫 int b; while ((b = in.read(buf, 0, buf.length)) != -1) {//read(buf,0,buf.length)帶參數(shù)的read返回的是字節(jié)的總長度;當全部讀完后返回的是-1; out.write(buf, 0, b); out.flush();// 最好加上 } in.close(); out.close(); } /** * 進行文件的拷貝,利用帶緩沖的字節(jié)流 * @param srcFile * @param destFile * @throws IOException */ public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{ if(!srcFile.exists()){ throw new IllegalArgumentException("文件:"+srcFile+"不存在"); } if(!srcFile.isFile()){ throw new IllegalArgumentException(srcFile+"不是文件"); } BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile)); int c ; while((c = bis.read())!=-1){ bos.write(c); bos.flush();//刷新緩沖區(qū) } bis.close(); bos.close(); } /** * 單字節(jié),不帶緩沖進行文件拷貝 * @param srcFile * @param destFile * @throws IOException */ public static void copyFileByByte(File srcFile,File destFile)throws IOException{ if(!srcFile.exists()){ throw new IllegalArgumentException("文件:"+srcFile+"不存在"); } if(!srcFile.isFile()){ throw new IllegalArgumentException(srcFile+"不是文件"); } FileInputStream in = new FileInputStream(srcFile); FileOutputStream out = new FileOutputStream(destFile); int c ; while((c = in.read())!=-1){//read()不帶參數(shù)的read返回的是讀到的字節(jié)內(nèi)容;當全部讀完后返回的都是是-1; out.write(c); out.flush(); } in.close(); out.close(); } }
測試類:
package com.study.io; import java.io.File; import java.io.IOException; import org.junit.Test; public class IOUtilTest { @Test public void testPrintHex() { try { IOUtil.printHex("D:\\Javaio\\FileUtils.java"); } catch (IOException e) { e.printStackTrace(); } } @Test public void testPrintHexByByteArray() { try { long start = System.currentTimeMillis();//當前時間與協(xié)調(diào)世界時 1970 年 1 月 1 日午夜之間的時間差(以毫秒為單位測量) //IOUtil.printHexByByteArray("e:\\javaio\\FileUtils.java"); //IOUtil.printHex("e:\\javaio\\1.mp3"); IOUtil.printHexByByteArray("e:\\javaio\\1.mp3"); System.out.println(); long end = System.currentTimeMillis(); System.out.println(end - start); } catch (IOException e) { e.printStackTrace(); } } @Test public void testCopyFile(){ try { IOUtil.copyFile(new File("d:\\javaio\\1.txt"), new File("d:\\javaio\\1copy.txt")); } catch (IOException e) { e.printStackTrace(); } } @Test public void testCopyFileByBuffer(){ try { long start = System.currentTimeMillis(); /*IOUtil.copyFileByByte(new File("e:\\javaio\\1.mp3"), new File( "e:\\javaio\\2.mp3"));*/ //兩萬多毫秒 /*IOUtil.copyFileByBuffer(new File("e:\\javaio\\1.mp3"), new File( "e:\\javaio\\3.mp3"));//一萬多毫秒*/ IOUtil.copyFile(new File("e:\\javaio\\1.mp3"), new File( "e:\\javaio\\4.mp3"));//7毫秒 long end = System.currentTimeMillis(); System.out.println(end - start ); } catch (IOException e) { e.printStackTrace(); } } }
五、字符流
package com.study.io; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class IsrAndOswDemo { public static void main(String[] args)throws IOException { FileInputStream in = new FileInputStream("e:\\javaio\\utf8.txt"); InputStreamReader isr = new InputStreamReader(in,"utf-8");//默認項目的編碼,操作的時候,要寫文件本身的編碼格式 FileOutputStream out = new FileOutputStream("e:\\javaio\\utf81.txt"); OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8"); /*int c ; while((c = isr.read())!=-1){ System.out.print((char)c); }*/ char[] buffer = new char[8*1024]; int c; /*批量讀取,放入buffer這個字符數(shù)組,從第0個位置開始放置,最多放buffer.length個返回的是讀到的字符的個數(shù)*/ while(( c = isr.read(buffer,0,buffer.length))!=-1){ String s = new String(buffer,0,c); System.out.print(s); osw.write(buffer,0,c); osw.flush(); } isr.close(); osw.close(); } }
字符流之文件讀寫流(FileReader/FileWriter)
字符流的過濾器
六、對象的序列化和反序列化
示例:
注意:
相關文章
SpringBoot 動態(tài)配置Profile環(huán)境的方式
這篇文章主要介紹了SpringBoot 動態(tài)配置Profile環(huán)境的方式,本文通過圖文實例相結(jié)合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-10-10Java?SSM實現(xiàn)前后端協(xié)議聯(lián)調(diào)詳解下篇
首先我們已經(jīng)知道,在現(xiàn)在流行的“前后端完全分離”架構(gòu)中,前后端聯(lián)調(diào)是一個不可能避免的問題,這篇文章主要介紹了Java?SSM實現(xiàn)前后端協(xié)議聯(lián)調(diào)過程2022-08-08解決異常處理問題:getReader()?has?already?been?called?for?this
這篇文章主要介紹了解決異常處理:getReader()?has?already?been?called?for?this問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Spring mvc整合tiles框架的簡單入門教程(maven)
這篇文章主要給大家介紹了關于Spring mvc整合tiles框架的簡單入門教程(maven),文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友可以參考借鑒,下面來一起看看詳細的介紹吧。2017-12-12使用Prometheus+Grafana的方法監(jiān)控Springboot應用教程詳解
這篇文章主要介紹了用Prometheus+Grafana的方法監(jiān)控Springboot應用,本文通過實例代碼詳解給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03