一、文件的編碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
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(); //這是把字符串轉換成字符數組,轉換成的字節序列用的是項目默認的編碼(這里為UTF-8) for ( byte b : bytes1) { //把字節(轉換成了int)以16進制的方式顯示 System.out.print(Integer.toHexString(b & 0xff )+ " " ); //& 0xff是為了把前面的24個0去掉只留下后八位 } System.out.println(); /*utf-8編碼中中文占用3個字節,英文占用1個字節*/ byte[] bytes2 = s.getBytes("utf-8");//這里會有異常展示,我們就throw這個異常 for (byte b : bytes2) { System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /*gbk編碼中文占用2個字節,英文占用1個字節*/ byte[] bytes3 = s.getBytes("gbk");//這里會有異常展示,我們就throw這個異常 for (byte b : bytes3) { System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /*utf-16be編碼中文占用2個字節,英文占用2個字節*/ byte[] bytes4 = s.getBytes("utf-16be");//這里會有異常展示,我們就throw這個異常 for (byte b : bytes4) { System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /*當你的字節序列是某種編碼時,這個時候想把字節序列變成字符串,也需要用這種編碼方式,否則會出現亂碼*/ String str1= new String(bytes4); //這時會使用項目默認的編碼來轉換,可能出現亂碼 System.out.println(str1); //要使用字節序列的編碼來進行轉換 String str2= new String(bytes4, "utf-16be" ); System.out.println(str2); } } |
分析:
* 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編碼(例如直接在電腦中創建文本文件)
二、File類的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package com.study.io; import java.io.File; /** * File類的使用 */ public class FileDemo { /*java.iO.File類表示文件或目錄 File類只用于表示文件或目錄的信息(名稱,大小等),不能用于文件內容的訪問。*/ public static void main(String[] args) { File file=new File("D:\\111");//創建文件對象時指定目錄需要用雙斜杠,因為“\”是轉義字符 /*目錄的中間的分隔符可以用雙斜杠,也可以用反斜杠,也可以用File.separator設置分隔符*/ // File file1=new File("d:"+File.separator); // System.out.println(file.exists());//exists()判斷文件或文件夾是否存在 if (!file.exists()){ //如果文件不存在 file.mkdir(); //創建文件夾mkdir(),還有mkdirs()創建多級目錄 } 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()的內容 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()); } } |
運行結果:
說明:
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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()方法用于列出當前目錄下的子目錄和文件(直接是子目錄的名稱,不包含子目錄下的內容),返回的是字符串數組 for (String string : fileNames) { System.out.println(string); }*/ //如果要遍歷子目錄下的內容就需要構造成File對象做遞歸操作,File提供了直接返回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); } } } } } |
測試類:
1
2
3
4
5
|
public class FileUtilsTest { public static void main(String[] args) throws IOException { FileUtils.listDirectory( new File( "D:\\ioStudy" )); } } |
運行結果:
三、RandomAccessFile類的使用
RandomAccessFile:java提供的對文件內容的訪問,既可以讀文件,也可以寫文件。
RandomAccessFile支持隨機訪問文件,可以訪問文件的任意位置。
注意 Java文件的模型:
運行結果:
1
12
[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
7f
ff
ff
ff
7f
ff
ff
ff
d6
d0
四、字節流(FileInputStream、FileOutputStream)
IO流可分為輸入流和輸出流。
這里又可分為字節流和字符流。
代碼示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
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-->具體實現了在文件上讀取數據 * FileOutputStream-->實現了向文件中寫出byte數據的方法 * 數據輸入輸出流: * DataOutputStream / DataInputStream:對"流"功能的擴展,可以更加方面的讀取int,long,字符等類型數據 * DataOutputStream writeInt()/writeDouble()/writeUTF() * 字節緩沖流: * BufferedInputStream & BufferedOutputStream * 這兩個流類位IO提供了帶緩沖區的操作,一般打開文件進行寫入或讀取操作時,都會加上緩沖,這種流模式提高了IO的性能 * 比如:從應用程序中把輸入放入文件,相當于將一缸水倒入到另一個缸中: FileOutputStream--->write()方法相當于一滴一滴地把水“轉移”過去 DataOutputStream-->writeXxx()方法會方便一些,相當于一瓢一瓢把水“轉移”過去 BufferedOutputStream--->write方法更方便,相當于一瓢一瓢先放入桶中(即緩存區),再從桶中倒入到另一個缸中,性能提高了 */ public class IOUtil { /** * 讀取指定文件內容,按照16進制輸出到控制臺 * 并且每輸出10個byte換行 * @param fileName * 單字節讀取不適合大文件,大文件效率很低 */ public static void printHex(String fileName) throws IOException{ //把文件作為字節流進行都操作 FileInputStream in= new FileInputStream(fileName); int b; int i= 1 ; while ((b=in.read())!=- 1 ){ /* 0xff換成2進制就是8個1,這樣與的話,其實就是取到了字符的低8位。 * oxf就是15, 小于15的數會轉換成一個16進制數, * 你的代碼里希望是固定的兩個16進制數,所以當只會產生一個時要加個0*/ if(b <= 0xf){ //單位數前面補0 System.out.print("0"); } //Integer.toHexString(b)將整型b轉換為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中批量讀取字節,放入到buf這個字節數組中, * 從第0個位置開始放,最多放buf.length個 * 返回的是讀到的字節的個數 */ /*int bytes = in.read(buf,0,buf.length);//一次性讀完,說明字節數組足夠大 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位,為了避免數據轉換錯誤,通過&0xff將高24位清零 */ if(j++%10==0){ System.out.println(); } } } in.close(); } /** * 文件拷貝,字節批量讀取 * @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);//文件不存在時,會直接創建;如果存在,刪除后建 byte[] buf = new byte[8 * 1024];//批量讀寫 int b; while ((b = in.read(buf, 0, buf.length)) != -1) {//read(buf,0,buf.length)帶參數的read返回的是字節的總長度;當全部讀完后返回的是-1; out.write(buf, 0, b); out.flush();// 最好加上 } in.close(); out.close(); } /** * 進行文件的拷貝,利用帶緩沖的字節流 * @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();//刷新緩沖區 } bis.close(); bos.close(); } /** * 單字節,不帶緩沖進行文件拷貝 * @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()不帶參數的read返回的是讀到的字節內容;當全部讀完后返回的都是是-1; out.write(c); out.flush(); } in.close(); out.close(); } } |
測試類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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這個字符數組,從第0個位置開始放置,最多放buffer.length個返回的是讀到的字符的個數*/ 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)
字符流的過濾器
六、對象的序列化和反序列化
示例:
注意:
原文鏈接:http://www.cnblogs.com/Qian123/archive/2016/07/11/5632028.html