1 package com.study.io; 2 3 4 /** 5 * 測試文件編碼 6 */ 7 public class EncodeDemo { 8 9 /** 10 * @param args 11 * @throws Exception 12 */ 13 public static void main(String[] args) throws Exception { 14 String s="好好學習ABC"; 15 byte[] bytes1=s.getBytes();//這是把字符串轉換成字符數組,轉換成的字節序列用的是項目默認的編碼(這裡為UTF-8) 16 for (byte b : bytes1) { 17 //把字節(轉換成了int)以16進制的方式顯示 18 System.out.print(Integer.toHexString(b & 0xff)+" ");//& 0xff是為了把前面的24個0去掉只留下後八位 19 } 20 System.out.println(); 21 /*utf-8編碼中中文占用3個字節,英文占用1個字節*/ 22 byte[] bytes2 = s.getBytes("utf-8");//這裡會有異常展示,我們就throw這個異常 23 for (byte b : bytes2) { 24 System.out.print(Integer.toHexString(b & 0xff)+" "); 25 } 26 System.out.println(); 27 /*gbk編碼中文占用2個字節,英文占用1個字節*/ 28 byte[] bytes3 = s.getBytes("gbk");//這裡會有異常展示,我們就throw這個異常 29 for (byte b : bytes3) { 30 System.out.print(Integer.toHexString(b & 0xff)+" "); 31 } 32 33 System.out.println(); 34 /*utf-16be編碼中文占用2個字節,英文占用2個字節*/ 35 byte[] bytes4 = s.getBytes("utf-16be");//這裡會有異常展示,我們就throw這個異常 36 for (byte b : bytes4) { 37 System.out.print(Integer.toHexString(b & 0xff)+" "); 38 } 39 40 System.out.println(); 41 /*當你的字節序列是某種編碼時,這個時候想把字節序列變成字符串,也需要用這種編碼方式,否則會出現亂碼*/ 42 String str1=new String(bytes4);//這時會使用項目默認的編碼來轉換,可能出現亂碼 43 System.out.println(str1); 44 //要使用字節序列的編碼來進行轉換 45 String str2=new String(bytes4,"utf-16be"); 46 System.out.println(str2); 47 } 48 }
分析:
* 1. “& 0xff”的解釋:
* 0xFF表示的是16進制(十進制是255),表示為二進制就是“11111111”。
* 那麼&符表示的是按位數進行與(同為1的時候返回1,否則返回0)
* 2.字節byte與int類型轉換:
* Integer.toHexString(b & 0xff)這裡先把byte類型的b和0xff進行了運算,然後Integer.toHexString取得了十六進制字符串
* 可以看出b & 0xFF運算後得出的仍然是個int,那麼為何要和 0xFF進行與運算呢?直接 Integer.toHexString(b);,將byte強轉為int不行嗎?答案是不行的.
* 其原因在於:1.byte的大小為8bits而int的大小為32bits;2.java的二進制采用的是補碼形式
* Integer.toHexString的參數是int,如果不進行&0xff,那麼當一個byte會轉換成int時,由於int是32位,而byte只有8位這時會進行補位。。。。。。
* 所以,一個byte跟0xff相與會先將那個byte轉化成整形運算,這樣,結果中的高的24個比特就總會被清0,於是結果總是我們想要的。
* 3.utf-8編碼:中文占用3個字節,英文占用1個字節
* gbk編碼:中文占用2個字節,英文占用1個字節
* Java采用雙字節編碼(就是Java中的一個字符占兩個字節)是utf-16be編碼。中文占用2個字節,英文占用2個字節
*
* 4.當你的字節序列是某種編碼時,這個時候想把字節序列變成字符串,也需要用這種編碼方式,否則會出現亂碼
* 5.文本文件 就是字節序列。可以是任意編碼的字節序列。
* 如果我們在中文機器上直接創建文本文件,那麼該文件只認識ANSI編碼(例如直接在電腦中創建文本文件)
1 package com.study.io; 2 3 import java.io.File; 4 5 /** 6 * File類的使用 7 */ 8 public class FileDemo { 9 /*java.iO.File類表示文件或目錄 10 File類只用於表示文件或目錄的信息(名稱,大小等),不能用於文件內容的訪問。*/ 11 public static void main(String[] args) { 12 File file=new File("D:\\111");//創建文件對象時指定目錄需要用雙斜槓,因為“\”是轉義字符 13 /*目錄的中間的分隔符可以用雙斜槓,也可以用反斜槓,也可以用File.separator設置分隔符*/ 14 // File file1=new File("d:"+File.separator); 15 // System.out.println(file.exists());//exists()判斷文件或文件夾是否存在 16 if(!file.exists()){//如果文件不存在 17 file.mkdir();//創建文件夾mkdir(),還有mkdirs()創建多級目錄 18 }else{ 19 file.delete();//刪除文件或文件夾 20 } 21 //判斷是否是一個目錄isDirectory,如果是目錄返回true,如果不是目錄或者目錄不存在返回false 22 System.out.println(file.isDirectory()); 23 //判斷是否是一個文件isFile 24 System.out.println(file.isFile()); 25 26 File file2=new File("D:\\222","123.txt"); 27 //常用API: 28 System.out.println(file);//打印的是file.toString()的內容 29 System.out.println(file.getAbsolutePath());//獲取絕對路徑 30 System.out.println(file.getName());//獲取文件名稱 31 System.out.println(file2.getName()); 32 System.out.println(file.getParent());//獲取父級絕對路徑 33 System.out.println(file2.getParentFile().getAbsolutePath()); 34 } 35 }
運行結果:
說明:
java.iO.File類表示文件或目錄
File類只用於表示文件或目錄的信息(名稱,大小等),不能用於文件內容的訪問。
常用的API:
1.創建File對象:File file=new File(String path);注意:File.seperater();獲取系統分隔符,如:“\”.
2.boolean file.exists();是否存在.
3.file.mkdir();或者file.mkdirs();創建目錄或多級目錄。
4.file.isDirectory()判斷是否是目錄
file.isFile()判斷是否是文件。
5.file.delete();刪除文件或目錄。
6.file.createNewFile();創建新文件。
7.file.getName()獲取文件名稱或目錄絕對路徑。
8.file.getAbsolutePath()獲取絕對路徑。
9.file.getParent();獲取父級絕對路徑。
❤❤1、遍歷目錄
1 package com.study.io; 2 3 import java.io.File; 4 import java.io.IOException; 5 6 /** 7 * File工具類 8 * 列出File類的常用操作,比如:過濾、遍歷等操作 9 */ 10 public class FileUtils { 11 /** 12 * 列出指定目錄下(包括其子目錄)的所有文件 13 * @param dir 14 * @throws IOException 15 */ 16 public static void listDirectory(File dir) throws IOException{ 17 if(!dir.exists()){//exists()方法用於判斷文件或目錄是否存在 18 throw new IllegalArgumentException("目錄:"+dir+"不存在"); 19 } 20 if(!dir.isDirectory()){//isDirectory()方法用於判斷File類的對象是否是目錄 21 throw new IllegalArgumentException(dir+"不是目錄"); 22 } 23 /*String[] fileNames = dir.list();//list()方法用於列出當前目錄下的子目錄和文件(直接是子目錄的名稱,不包含子目錄下的內容),返回的是字符串數組 24 for (String string : fileNames) { 25 System.out.println(string); 26 }*/ 27 28 //如果要遍歷子目錄下的內容就需要構造成File對象做遞歸操作,File提供了直接返回File對象的API 29 File[] listFiles = dir.listFiles();//返回的是直接子目錄(文件)的抽象 30 if(listFiles !=null && listFiles.length >0){ 31 for (File file : listFiles) { 32 /*System.out.println(file);*/ 33 if(file.isDirectory()){ 34 //遞歸 35 listDirectory(file); 36 }else{ 37 System.out.println(file); 38 } 39 } 40 } 41 } 42 }
測試類:
1 public class FileUtilsTest1 { 2 public static void main(String[] args) throws IOException { 3 FileUtils.listDirectory(new File("D:\\ioStudy")); 4 } 5 }
運行結果:
RandomAccessFile:java提供的對文件內容的訪問,既可以讀文件,也可以寫文件。
RandomAccessFile支持隨機訪問文件,可以訪問文件的任意位置。
注意 Java文件的模型:
示例代碼:
1 package com.study.io; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.RandomAccessFile; 6 import java.util.Arrays; 7 8 9 /** 10 * RandomAccessFile 11 */ 12 public class RandomAccessFileDemo { 13 public static void main(String[] args) throws IOException{ 14 File demo = new File("demo"); 15 if(!demo.exists()){ 16 demo.mkdir(); 17 } 18 File file = new File(demo,"raf.dat"); 19 if(!file.exists()){ 20 file.createNewFile(); 21 } 22 23 RandomAccessFile raf = new RandomAccessFile(file, "rw"); 24 //指針的位置 25 System.out.println(raf.getFilePointer()); 26 27 raf.write('A');//只寫了一個字節 28 System.out.println(raf.getFilePointer()); 29 raf.write('B'); 30 31 int i = 0x7fffffff; 32 //用write方法每次只能寫一個字節,如果要把i寫進去就得寫4次 33 raf.write(i >>> 24);//高8位 34 raf.write(i >>> 16); 35 raf.write(i >>> 8); 36 raf.write(i); 37 System.out.println(raf.getFilePointer()); 38 39 //可以直接寫一個int 40 raf.writeInt(i); 41 42 String s = "中"; 43 byte[] gbk = s.getBytes("gbk"); 44 raf.write(gbk); 45 System.out.println(raf.length()); 46 47 //讀文件,必須把指針移到頭部 48 raf.seek(0); 49 //一次性讀取,把文件中的內容都讀到字節數組中 50 byte[] buf = new byte[(int)raf.length()]; 51 raf.read(buf); 52 53 System.out.println(Arrays.toString(buf)); 54 for (byte b : buf) { 55 System.out.println(Integer.toHexString(b & 0xff)+" "); 56 } 57 raf.close(); 58 } 59 }
運行結果:
0 1 6 12 [65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48] 41 42 7f ff ff ff 7f ff ff ff d6 d0 View CodeIO流可分為輸入流和輸出流。
這裡又可分為字節流和字符流。
代碼示例:
1 package com.study.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 10 /** 11 * IO工具類 12 * ❤文件輸入輸出流: 13 * FileInputStream-->具體實現了在文件上讀取數據 14 * FileOutputStream-->實現了向文件中寫出byte數據的方法 15 * ❤數據輸入輸出流: 16 * DataOutputStream / DataInputStream:對"流"功能的擴展,可以更加方面的讀取int,long,字符等類型數據 17 * DataOutputStream writeInt()/writeDouble()/writeUTF() 18 * ❤字節緩沖流: 19 * BufferedInputStream & BufferedOutputStream 20 * 這兩個流類位IO提供了帶緩沖區的操作,一般打開文件進行寫入或讀取操作時,都會加上緩沖,這種流模式提高了IO的性能 21 * 比如:從應用程序中把輸入放入文件,相當於將一缸水倒入到另一個缸中: 22 FileOutputStream--->write()方法相當於一滴一滴地把水“轉移”過去 23 DataOutputStream-->writeXxx()方法會方便一些,相當於一瓢一瓢把水“轉移”過去 24 BufferedOutputStream--->write方法更方便,相當於一瓢一瓢先放入桶中(即緩存區),再從桶中倒入到另一個缸中,性能提高了 25 */ 26 public class IOUtil { 27 28 /** 29 * 讀取指定文件內容,按照16進制輸出到控制台 30 * 並且每輸出10個byte換行 31 * @param fileName 32 * 單字節讀取不適合大文件,大文件效率很低 33 */ 34 public static void printHex(String fileName)throws IOException{ 35 //把文件作為字節流進行都操作 36 FileInputStream in=new FileInputStream(fileName); 37 int b; 38 int i=1; 39 while((b=in.read())!=-1){ 40 /* 0xff換成2進制就是8個1,這樣與的話,其實就是取到了字符的低8位。 41 * oxf就是15, 小於15的數會轉換成一個16進制數, 42 * 你的代碼裡希望是固定的兩個16進制數,所以當只會產生一個時要加個0*/ 43 if(b <= 0xf){ 44 //單位數前面補0 45 System.out.print("0"); 46 } 47 //Integer.toHexString(b)將整型b轉換為16進制表示的字符串 48 System.out.print(Integer.toHexString(b)+" "); 49 if(i++%10==0){ 50 System.out.println(); 51 } 52 } 53 in.close();//文件讀寫完成以後一定要關閉 54 } 55 56 /** 57 * 批量讀取,對大文件而言效率高,也是我們最常用的讀文件的方式 58 * @param fileName 59 * @throws IOException 60 */ 61 public static void printHexByByteArray(String fileName)throws IOException{ 62 FileInputStream in = new FileInputStream(fileName); 63 byte[] buf = new byte[8 * 1024]; 64 /*從in中批量讀取字節,放入到buf這個字節數組中, 65 * 從第0個位置開始放,最多放buf.length個 66 * 返回的是讀到的字節的個數 67 */ 68 /*int bytes = in.read(buf,0,buf.length);//一次性讀完,說明字節數組足夠大 69 int j = 1; 70 for(int i = 0; i < bytes;i++){ 71 System.out.print(Integer.toHexString(buf[i] & 0xff)+" "); 72 if(j++%10==0){ 73 System.out.println(); 74 } 75 }*/ 76 int bytes = 0; 77 int j = 1; 78 while((bytes = in.read(buf,0,buf.length))!=-1){ 79 for(int i = 0 ; i < bytes;i++){ 80 System.out.print(Integer.toHexString(buf[i] & 0xff)+" "); 81 /** 82 * & 0xff:byte類型8位,int類型32位,為了避免數據轉換錯誤,通過&0xff將高24位清零 83 */ 84 if(j++%10==0){ 85 System.out.println(); 86 } 87 } 88 } 89 in.close(); 90 } 91 92 /** 93 * 文件拷貝,字節批量讀取 94 * @param srcFile 95 * @param destFile 96 * @throws IOException 97 */ 98 public static void copyFile(File srcFile, File destFile) throws IOException { 99 if (!srcFile.exists()) { 100 throw new IllegalArgumentException("文件:" + srcFile + "不存在"); 101 } 102 if (!srcFile.isFile()) { 103 throw new IllegalArgumentException(srcFile + "不是文件"); 104 } 105 FileInputStream in = new FileInputStream(srcFile); 106 FileOutputStream out = new FileOutputStream(destFile);//文件不存在時,會直接創建;如果存在,刪除後建 107 byte[] buf = new byte[8 * 1024];//批量讀寫 108 int b; 109 while ((b = in.read(buf, 0, buf.length)) != -1) {//read(buf,0,buf.length)帶參數的read返回的是字節的總長度;當全部讀完後返回的是-1; 110 out.write(buf, 0, b); 111 out.flush();// 最好加上 112 } 113 in.close(); 114 out.close(); 115 } 116 117 /** 118 * 進行文件的拷貝,利用帶緩沖的字節流 119 * @param srcFile 120 * @param destFile 121 * @throws IOException 122 */ 123 public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{ 124 if(!srcFile.exists()){ 125 throw new IllegalArgumentException("文件:"+srcFile+"不存在"); 126 } 127 if(!srcFile.isFile()){ 128 throw new IllegalArgumentException(srcFile+"不是文件"); 129 } 130 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile)); 131 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile)); 132 int c ; 133 while((c = bis.read())!=-1){ 134 bos.write(c); 135 bos.flush();//刷新緩沖區 136 } 137 bis.close(); 138 bos.close(); 139 } 140 141 /** 142 * 單字節,不帶緩沖進行文件拷貝 143 * @param srcFile 144 * @param destFile 145 * @throws IOException 146 */ 147 public static void copyFileByByte(File srcFile,File destFile)throws IOException{ 148 if(!srcFile.exists()){ 149 throw new IllegalArgumentException("文件:"+srcFile+"不存在"); 150 } 151 if(!srcFile.isFile()){ 152 throw new IllegalArgumentException(srcFile+"不是文件"); 153 } 154 FileInputStream in = new FileInputStream(srcFile); 155 FileOutputStream out = new FileOutputStream(destFile); 156 int c ; 157 while((c = in.read())!=-1){//read()不帶參數的read返回的是讀到的字節內容;當全部讀完後返回的都是是-1; 158 out.write(c); 159 out.flush(); 160 } 161 in.close(); 162 out.close(); 163 } 164 }
測試類:
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();//當前時間與協調世界時 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(); } } }
1 package com.study.io; 2 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.io.OutputStreamWriter; 8 9 public class IsrAndOswDemo { 10 public static void main(String[] args)throws IOException { 11 FileInputStream in = new FileInputStream("e:\\javaio\\utf8.txt"); 12 InputStreamReader isr = new InputStreamReader(in,"utf-8");//默認項目的編碼,操作的時候,要寫文件本身的編碼格式 13 14 FileOutputStream out = new FileOutputStream("e:\\javaio\\utf81.txt"); 15 OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8"); 16 /*int c ; 17 while((c = isr.read())!=-1){ 18 System.out.print((char)c); 19 }*/ 20 char[] buffer = new char[8*1024]; 21 int c; 22 /*批量讀取,放入buffer這個字符數組,從第0個位置開始放置,最多放buffer.length個返回的是讀到的字符的個數*/ 23 while(( c = isr.read(buffer,0,buffer.length))!=-1){ 24 String s = new String(buffer,0,c); 25 System.out.print(s); 26 osw.write(buffer,0,c); 27 osw.flush(); 28 } 29 isr.close(); 30 osw.close(); 31 32 } 33 34 }
❤ 字符流之文件讀寫流(FileReader/FileWriter)
❤ 字符流的過濾器
示例:
注意: