1. 編碼問題
從一種形式或格式轉(zhuǎn)換為另一種形式的過程也稱為計(jì)算機(jī)編程語言的代碼簡稱編碼
。而這個(gè)轉(zhuǎn)換的方式就是編碼方式。
將字符串“例子ABC”分別以gbk
、utf-8
、utf-16be
編碼方式轉(zhuǎn)化成字節(jié),如下:
public class Coding {
public static void printByEncoding(String s, String encoding){
try {
byte[] bytes = s.getBytes(encoding);
System.out.print("encoding " + encoding + " : ");
for (byte b : bytes) {
//把字節(jié)(轉(zhuǎn)換成了int)以16進(jìn)制的方式顯示
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
System.out.println();
}catch (UnsupportedEncodingException e){
System.out.println("unsupportded encoding: " + encoding);
}
}
public static void main(String[] args) {
String s = "例子ABC";
//gbk編碼:中文兩個(gè)字節(jié),英文一個(gè)字節(jié)
Coding.printByEncoding(s, "gbk");
//utf-8編碼:中文三個(gè)字節(jié),英文一個(gè)字節(jié)
Coding.printByEncoding(s, "utf-8");
// utf-16be編碼,中文兩個(gè)字節(jié),英文兩個(gè)字節(jié)
Coding.printByEncoding(s, "utf-16be");
}
輸出結(jié)果為:
encoding gbk : c0 fd d7 d3 41 42 43
encoding utf-8 : e4 be 8b e5 ad 90 41 42 43
encoding utf-16be : 4f 8b 5b 50 0 41 0 42 0 43
當(dāng)你的字節(jié)序列是某種編碼時(shí),這時(shí)候想把字節(jié)序列變成字符串,也需要這種編碼方式,否則會出現(xiàn)亂碼
try {
String str1 = new String(s.getBytes("utf-16be"));
System.out.println(str1);
String str2 = new String(s.getBytes("utf-16be"), "utf-16be");
System.out.println(str2);
}catch (UnsupportedEncodingException e){
System.out.println("unsupportded encoding: " );
}
輸出結(jié)果為:
O?[P A B C
例子ABC
文本文件就是字節(jié)序列,它可以是任何編碼的字節(jié)序列。
2. File類
java.io.File
類用于表示文件(目錄)。File類只用于表示文件(目錄)的信息(名稱、大小),不能用于文件內(nèi)容的訪問。
File file1 = new File("文件/目錄路徑");
File file2 = new File(File parent, String child);
File file3 = new File(String parent, String child)
方法 | 描述 |
---|---|
boolean exists() | 判斷文件/目錄 是否存在 |
boolean mkdir() | 創(chuàng)建目錄 |
void createNewFile() | 創(chuàng)建目錄 |
delete() | 刪除文件/目錄 |
boolean isDirectory() | 是否是一個(gè)目錄,如果不是目錄or目錄不存在返回false |
boolean isFile() | 是否是一個(gè)文件 |
String getName() | 返回文件/目錄名。 |
String getAbsolutePath() | 返回抽象路徑名的絕對路徑名字符串。 |
String getParent() / File getParentFile() | 獲取父路徑 |
long lastModified() | 返回此抽象路徑名表示的文件最后一次被修改的時(shí)間。 |
String[] list() | 返回由包含在目錄中的文件和目錄的名稱所組成的字符串?dāng)?shù)組 |
File[] listFiles() | 返回一個(gè)抽象路徑名數(shù)組,這些路徑名表示此抽象路徑名所表示目錄中的文件。 |
...... | ...... |
eg:遍歷目錄
package com.company;
import java.io.File;
import java.util.Stack;
/**
* FileItem表示 文件和文件在第幾層
*/
public class FileItem {
public File file;
public int depth ;
public FileItem(File file, int depth) {
this.file = file;
this.depth = depth;
}
//遍歷文件or目錄
public static void printFiles(String path){
//用于存放待訪問的節(jié)點(diǎn)
Stack<FileItem> stack = new Stack<FileItem>();
//根節(jié)點(diǎn)入棧
stack.push( new FileItem(new File("F:\\study"), 0) );
while(!stack.empty() ) {
FileItem item = stack.pop();
File file = item.file;
int depth = item.depth;
//打出文件名,按層數(shù)縮進(jìn)
System.out.println(new String(" ".repeat(2*depth) + file.getName()) );
if(file.exists() && file.isDirectory()){
//遍歷下一層
File[] fileList = file.listFiles();
for(File it: fileList){
//下一層入棧
stack.push( new FileItem(it, depth+1) );
}
}
}
}
public static void main(String[] args) {
printFiles("F://");
}
}
3. RandomAccessFile
RandomAccessFile是Java提供的對文件內(nèi)容的訪問,既可以讀文件,也可以寫文件。
RandomAccessFile支持隨機(jī)訪問文件,即可以訪問文件的任意位置。
- (1) java文件模型
在硬盤上的文件是bye bye bye存儲的,是數(shù)據(jù)的集合。 - (2) 打開文件
打開文件時(shí),可以選擇兩種模式:“rw"(讀寫),"r"(只讀)。
RandomAccessFile raf = new RandomAccessFile(file, "rw");
由于RandomAccessFile支持隨機(jī)訪問文件,需要一個(gè)文件指針來指定位置。打開文件時(shí)指針在開題pointer = 0;
- (3) 寫方法
raf.write(int) //只寫一個(gè)字節(jié),同時(shí)指針指向下一個(gè)位置。
- (4) 讀方法
int b = raf.read(); //讀一個(gè)字節(jié)
- (5) 文件讀寫完成后一定要關(guān)閉。
4. 字節(jié)流
4.1 InputStream和OutputStream
InputStream 和 OutputStream為各種輸入輸出字節(jié)流的基類,所有字節(jié)流都繼承這兩個(gè)基類。而且InputStream 和 OutputStream為抽象類
,不進(jìn)行具體的實(shí)現(xiàn)。
InputStream抽象了應(yīng)用程序讀取數(shù)據(jù)的方式。
OutputStream抽象了應(yīng)用程序?qū)懗鰯?shù)據(jù)的方式。
- 輸入流常用方法
方法名 | 描述 |
---|---|
int read() throws IOException | 讀取一個(gè)字節(jié)無符號填充到int低八位,-1是EOF |
int read( byte[] buf ) throws IOException | 讀取數(shù)據(jù)填充到字節(jié)數(shù)組buf |
int read(byte[] buf, int start, int size) throws IOException | /讀取數(shù)據(jù)填充到字節(jié)數(shù)組buf |
void close() throws IOException | 關(guān)閉輸入流 |
- 輸出流基本方法
方法名 | 描述 |
---|---|
void write(int b) throws IOException | 寫出一個(gè)byte到流,b的低八位 |
void write( byte[] buf ) throws IOException | 將buf字節(jié)數(shù)組都寫入到流 |
void write(byte[] buf, int start, int size) throws IOException | 將buf字節(jié)數(shù)組都寫入到流 |
void close() throws IOException | 關(guān)閉輸出流 |
4.2 FileInputStream和FileOutputStream
FileInputStream具體實(shí)現(xiàn)了在文件上讀取數(shù)據(jù)。
FileOutputStream具體實(shí)現(xiàn)了將byte數(shù)據(jù)寫入文件.
- 讀取文件
/**
* 通過int讀取指定文件內(nèi)容,按照16進(jìn)制輸出到控制臺
*/
public static void printHexByInt(String filename) throws IOException{
//把文件作為字節(jié)流進(jìn)行讀操作
FileInputStream in = new FileInputStream(filename);
int b;
while ( (b=in.read()) != -1 ){
System.out.print(Integer.toHexString(b) + " ");
}
in.close();
}
/**
* 通過byte讀取指定文件內(nèi)容,按照16進(jìn)制輸出到控制臺
*/
public static void printHexByBytes(String filename) throws IOException{
//把文件作為字節(jié)流進(jìn)行讀操作
FileInputStream in = new FileInputStream(filename);
byte[] buf = new byte[1024]; //隨便大小都可,大一點(diǎn)可能更快
//從in中批量讀取字節(jié), 最多讀取 buf.length個(gè),返回讀到的數(shù)據(jù)的個(gè)數(shù)
//int bytes = in.read(buf);
int bytes = 0;
while ( ( bytes = in.read(buf) ) != -1){
for(int i = 0; i < bytes; i++){
System.out.print( Integer.toHexString(buf[i] &0x00ff)+ " ");
}
}
}
- 寫入文件
//如果該文件不存在,則直接創(chuàng)建;如果存在,刪除后創(chuàng)建
FileOutputStream out = new FileOutputStream("out.dat");
//如果該文件不存在,則直接創(chuàng)建;如果存在,在后面繼續(xù)寫
FileOutputStream out2 = new FileOutputStream("out2.dat",true);
out.write('A'); //寫出了‘A’的低八位
//write只能寫八位,那么寫一個(gè)int需要4次每次8位
int a = 10;
out.write(a >>> 24);
out.write(a >>> 16);
out.write(a >>> 8 );
out.write(a );
//寫入byte數(shù)組
byte [] gbk = "中國".getBytes("gbk");
out.write(gbk);
out.close();
- 拷貝一個(gè)文件
try {
InputStream in = new FileInputStream("a.txt");
OutputStream out = new FileOutputStream("b.txt");
byte[] buf = new byte[1024];
int bytes;
while( (bytes = in.read(buf)) != -1){
out.write(buf);
out.flush();
}
in.close();
out.close();
}catch (FileNotFoundException e1){
e1.printStackTrace();
}catch (IOException e2){
e2.printStackTrace();
}
4.3 DataInputStream和DataOutputStream
對"流"功能的擴(kuò)展,可以更加方便地讀取int、long、字符等類型數(shù)據(jù)。
- DataInputStream: readByte()/readInt() / readDouble() / readUTF()...
- DataOutputStream:writeByte()/writeInt() / writeDouble() / writeUTF()...
4.2 字節(jié)緩沖流BufferedInputStream和BufferedOutputStream
為IO提供了帶緩沖區(qū)的操作,一般打開文件進(jìn)行寫入或讀取操作時(shí),都會加上緩沖,這種流模式提高了IO的性能。
從應(yīng)用程序中把輸入放入文件,相當(dāng)于將一缸水倒入到另一缸水中:
- FileOutputStream --> write()方法相當(dāng)于一滴一滴地把水轉(zhuǎn)移過去
- DataOutputStream->writeXxx()方法會方便點(diǎn),相當(dāng)于一瓢一瓢地將水轉(zhuǎn)移過去。
- BufferedOutputStream-->write方法更方便,相當(dāng)于一瓢一瓢先放入桶中,再從桶中倒入缸中。
拷貝文件:
try {
BufferedInputStream is = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("b.txt"));
int c;
while( (c=is.read())!= -1){
os.write(c);
os.flush(); //刷新緩存區(qū)
}
is.close();
os.close();
}catch (FileNotFoundException e1){
e1.printStackTrace();
}catch (IOException e2){
e2.printStackTrace();
}
5. 字符流Reader/Writer
5.1 文本文件
- java的文本(char)是16位無符號整數(shù),是字符的unicode編碼(雙字節(jié)編碼)。
- 文件是 byte byte byte...的數(shù)據(jù)序列。
- 文本文件是文本(char)序列按照某種編碼方案(utf-8,utf-16be,gbk) 序列號為byte 的存儲結(jié)構(gòu)。
字符的處理,一次處理一個(gè)字符。但是字符的底層任然是基本的字節(jié)序列 。
5.2 InputStreamReader和OutputStreamWriter
InputStreamReader 完成byte流解析為char流,按照編碼解析。
OutputStreamWriter 提供char流到byte流,按照編碼處理。
try {
FileInputStream is = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(is,"gbk");//默認(rèn)為gbk
//第一種方法
int c;
while( (c = isr.read()) != -1){
System.out.println( (char)c);
}
//第二種方法
char[] buffer = new char[1024];
int n;
while( (n = isr.read(buffer)) !=-1 ){
String s = new String(buffer, 0, n);
System.out.println( s );
}
is.close();
isr.close();
}catch (FileNotFoundException e1){
e1.printStackTrace();
}catch (IOException e2){
e2.printStackTrace();
}
5.3 BufferedReader / BufferedWriter
- BufferedReader : readLine 一次第一行
- BufferedWriter/PrintWriter:寫一行
6.對象的序列化和反序列化
對象序列化,就是將Object轉(zhuǎn)換成byte序列,反之叫對象的反序列化 。
- 序列化流(ObjectOutputStream),是過濾流。--- writeObject
- 反序列化流(ObjectInputStream) --- readObject
對象必須實(shí)現(xiàn)序列化接口Serializable
,才能序列化,否則將會出現(xiàn)異常。
- 序列化:
public class Student implements Serializable {
private String stuno;
private String stuname;
private int stuage;
public Student(String stuno, String stuname, int stuage) {
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
- 將Object寫入文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
Student stu = new Student("10000","loserwang",20);
oos.writeObject(stu);
oos.flush();
oos.close();
- 從文件中讀取Object
String file = "obj.txt";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Student s = (Student) ois.readObject();
System.out.println(s);
添加transient
該元素不會被JVM默認(rèn)序列化
private transient int name;