了解
- 文件的編碼
- File類的使用
- RandomAccessFile類的使用
- 字節流
- 字符流
- 對象的序列化和反序列化
文件的編碼
有時候我們打開一個文件或者是網頁發現里面出現的都是亂碼。其原因是編輯文件時所采用的編碼方法和打開文件時所采用的解碼方式不同,所以造成打開文件看到的都是亂碼。
在Java中,GBK編碼中文占用2個字節,英文占用1個字節,UTF-8編碼中,中文占用3個字節,英文占用1個字節。
范例
import java.io.UnsupportedEncodingException;
/**
* Created by 99479 on 2017/7/11.
*/
public class EncodeDemo01 {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "蒲杰ABC";
byte [] bytes = s.getBytes("gbk");//轉換成字節序列,用的是項目默認的編碼
for (byte b:
bytes) {
//把字節(轉換了int)以16進制的方式顯示
System.out.print (Integer.toHexString(b & 0xff)+" ");
}
System.out.println();
for (byte b:
s.getBytes("utf-8")) {
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
System.out.println();
/**
* 當你的字節序列是某種編碼時,這個時候想把字節序列變成字符串,也需要用這種編碼方式,否者會出現亂碼
*/
String s1 = new String(bytes);//用項目的默認編碼
System.out.println(s1); //輸出亂碼
String s2 = new String(bytes,"gbk");
System.out.println(s2);
/**
* 文本文件 就是字節序列
* 可以是任意編碼的字節序列
* 入股我們在中文機器機器上直接創建文本文件,那么該文本文件只認識snsi編碼
*/
}
}
輸出
c6 d1 bd dc 41 42 43
e8 92 b2 e6 9d b0 41 42 43
???ABC
蒲杰ABC
File類的使用##
在Java中,File類用于表示文件或者表示目錄。在java.io.File包中。File類只用于表示文件(目錄)的信息(名稱、大小等),不能用于文件內容的訪問。下面的范例都演示File類的基本操作。
范例1,常用API
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/11.
*/
public class FileDemo {
public static void main(String[] args) {
//了解構造函數
File file = new File("d:"+File.separator+"javaio");
//查看文件是否存在
System.out.println(file.getName()+" 是否存在:" +file.exists());
//如果不存在就創建此文件夾,存在就刪除此文件
if(!file.exists()){
file.mkdir();//創建文件夾
//判斷是否時一個目錄
System.out.println(file.getName()+" 是否是一個文件夾:" + file.isDirectory());
//判斷是否時一個文件
System.out.println(file.getName()+" 是否是一個文件:" + file.isFile());
}else {
boolean isDelete = file.delete();
System.out.println(file.getName()+" 是否刪除成功:" + isDelete);
}
//創建一個文件對象
File file1 = new File("d:"+File.separator+"日記.txt");
System.out.println(file1.getName() + " 文件是否存在:" + file1.exists());
if (!file1.exists()){
try {
boolean isCreat = file1.createNewFile();
System.out.println(file1.getName()+" 是否創建成功:"+ isCreat);
System.out.println(file1.getName()+" 是否是一個文件夾:" + file1.isDirectory());
System.out.println(file1.getName()+" 是否是一個文件:" + file.isFile());
System.out.println(file1.getName()+" 的絕對路徑:" + file1.getAbsolutePath());
System.out.println(file1.getName()+" 的父路徑:" + file1.getParent());
} catch (IOException e) {
e.printStackTrace();
}
}else {
boolean isDelete = file1.delete();
System.out.println(file1.getName()+" 是否刪除成功:"+ isDelete);
}
}
}
輸出
javaio 是否存在:true
javaio 是否刪除成功:true
日記.txt 文件是否存在:false
日記.txt 是否創建成功:true
日記.txt 是否是一個文件夾:false
日記.txt 是否是一個文件:false
日記.txt 的絕對路徑:d:\日記.txt
日記.txt 的父路徑:d:\
范例2,遍歷目錄
FileUtil.java
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/12.
* 列出File的一些常用操作比如過濾、遍歷等操作
*/
public class FileUtils {
/**
* 列出某個目錄的所有文件或者包括子目錄中的所有文件和文件夾
* @param dir
* @throws IOException
*/
public static void listDirectory(File dir) throws IOException{
if (!dir.exists()){
throw new IllegalArgumentException("目錄:"+dir+"不存在");
}
if (!dir.isDirectory()){
throw new IllegalArgumentException(dir+"不是目錄");
}
String [] filenames = dir.list();
File[] files = dir.listFiles();
for (File file: files) {
if (file.isFile()){
System.out.println("文件: "+file.getAbsolutePath());
}else if (file.isDirectory()){
System.out.println("文件夾:"+file.getAbsolutePath());
//遞歸調用
listDirectory(file);
}
}
}
}
FileUtilTest01.java
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/12.
*/
public class FileUtilsTest01 {
public static void main(String[] args) {
try {
FileUtils.listDirectory(new File("D:"+File.separator+"迅雷下載"+File.separator+"殺不死"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
輸出
文件夾:D:\迅雷下載\殺不死\test
文件: D:\迅雷下載\殺不死\test\0.0.txt
文件夾:D:\迅雷下載\殺不死\test\新建文件夾
文件: D:\迅雷下載\殺不死\test\新建文件夾\tstsbg.txt
文件: D:\迅雷下載\殺不死\[殺BS]第01集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第02集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第03集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第04集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第05集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第06集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第07集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第08集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第09集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第10集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第11集_bd.mp4
文件: D:\迅雷下載\殺不死\[殺BS]第12集_bd.mp4
RandomAccessFile基本操作
RandomAccessFile時Java提供的對文件內容的訪問類,既可以讀文件,也可以寫文件。RandomAccessFile支持隨機訪問文件,可以訪問文件的任意位置
(1)Java的文件模型,
在硬盤上的文件是以byte byte byte存儲的,時數據的集合。
(2)打開文件有兩種模式
1、“rw”讀寫。2、“r”只讀。
在使用RandomAccessFile操作文件的時候不僅要傳入要操作文件的路徑,還要傳入操作文件的方式,例:RandomAccessFile raf = new RandomAccessFile("file","rw");
由于是隨機訪問文件,它包含一個文件指針,打開文件時指針在開頭 pointer = 0;
(3)、寫方法
raf.write(int) ---> 只寫一個字節(后8位),同時指針指向下一個位置,準備再次寫入。
(4)、讀方法
int b = raf.read() ---> 讀一個字節
(5)、文件讀寫完成后一定要關閉(Oracle官方說明),以防出現意想不到的錯誤。
范例
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
/**
* Created by 99479 on 2017/7/12.
*/
public class RafDemo {
public static void main(String[] args) throws IOException {
File demo = new File("demo");
if (!demo.exists()){
demo.mkdir();
}
//以demo為父目錄
File file = new File(demo,"raf.dat");
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(file.getAbsolutePath());
RandomAccessFile raf = new RandomAccessFile(file,"rw");
//指針的位置
System.out.println("指針的位置"+raf.getFilePointer());
System.out.println("開始寫文件...");
raf.write('A');//只寫了一個字節
System.out.println("指針的位置"+raf.getFilePointer());
raf.write('B');
int i=0x7fffffff;
//用write方法每次只寫一個字節,如果要把i寫進去就得寫4次
raf.write(i>>>24);//高八位
raf.write(i>>>16);
raf.write(i>>>8);
raf.write(i);
System.out.println("指針的位置"+raf.getFilePointer());
//可以直接寫一個int
raf.writeInt(i);
//寫一個中文字符(先轉換成字節)
String s = "中";
byte [] gbk = s.getBytes("gbk");
raf.write(gbk);
System.out.println("文件的長度: "+raf.length());
System.out.println("開始讀文件...");
//讀文件,必須把指針移到頭部
raf.seek(0);
//一次性讀取,把文件中的內容都讀到字節數組中
byte [] buf = new byte[(int)(raf.length())];
raf.read(buf);
System.out.println(Arrays.toString(buf));
//關閉文件操作流
raf.close();
}
}
輸出
D:\IdeaProjects\TestDemo\demo\raf.dat
指針的位置0
開始寫文件...
指針的位置1
指針的位置6
文件的長度: 12
開始讀文件...
[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
首先要了解流的概念,在Java中IO流就是輸入輸出流,在這里面也分為了字節流、字符流。
字節流##
(1)字節流又分為InputStream、OutputStream兩個抽象類
InputStream:抽象了應用程序讀取數據的方式。
OutputStream:抽象了應用程序寫出數據的方式。
(2)讀到返回值為-1就表示已經讀到結尾。
(3)字節輸入流基本方法:
- int b = in.read();讀取一個字節無符號填充到int低八位。讀到-1結束
- in.read(byte [] buf)讀取數據填充到字節數組
- in.read(byte [] buf,int start,int size)讀取數據填充到字節數組buf,從buf的start位置開始存放size長度的數據。
(4)字節輸出流的基本方法:
- out.write(int b)寫出一個byte到流,b的低八位
- out.write(byte [] buf)將buf字節數據都寫入到流
- out.write(byte [] buf,int start,int size)字節數組buf從start位置開始寫size長度的字節流。
了解
- 字節流之文件輸入流FileInputStream
- 字節流之文件輸出流FileOutputStream
- 字節流之數據輸入輸出流
- 字節緩沖流
字節流之文件輸入流FileInputStream
FileInputStream繼承了抽象類InputStream。具體實現了在文件上讀取數據。
范例
IOUtil
import java.io.FileInputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
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){
System.out.print(Integer.toHexString(b)+" ");
if (i++%10 == 0){
System.out.println();
}
}
//關閉輸入流
in.close();
}
public static void printHexByByteArray(String fileName)throws IOException{
FileInputStream in = new FileInputStream(fileName);
byte [] buf = new byte[20*1024];
//從in中批量讀取字節,放入到buf這個字節數組中,
// 從第0個位置開始放,最多放buf.length個,
//返回的是讀到的字節的個數
int bytes = in.read(buf,0,buf.length);//一次性讀完,說明字節數組足夠大
int j = 1;
for (int i = 0 ; i < bytes ; i++){
if (buf[i] <= 0xf){
System.out.print("0");
}
System.out.print(Integer.toHexString(buf[i])+" ");
if (j++%10 == 0){
System.out.println();
}
}
}
}
IOUtilTest01
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtilTest01 {
public static void main(String[] args) {
try {
IOUtil.printHex("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
} catch (IOException e) {
e.printStackTrace();
}
}
}
IOUtilTest02
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtilTest02 {
public static void main(String[] args) {
try {
IOUtil.printHexByByteArray("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
} catch (IOException e) {
e.printStackTrace();
}
}
}
字節流之文件輸出流FileOutputStream
FileOutputStream實現了向文件中寫出byte數據的方法,繼承了OutputStream。
范例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class FileOutDemo01 {
public static void main(String[] args) throws IOException {
//如果文件不存在,則直接創建,如果存在,刪除后創建
FileOutputStream out = new FileOutputStream("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
//如果是追加內容,則使用
// FileOutputStream out = new FileOutputStream("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat",true);
out.write('A');//寫出了A的低八位
out.write('B');//寫出了'B'的低八位
int a = 10;//write只能寫八位,那么寫一個int需要寫4次每次8位
out.write(a >>> 24);
out.write(a >>> 16);
out.write(a >>> 8);
out.write(a);
byte[] gbk = "中國".getBytes("gbk");
out.write(gbk);
out.close();
IOUtil.printHex("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
}
}
輸出
41 42 0 0 0 a d6 d0 b9 fa
范例:利用文件輸入流、文件輸出流實現文件的拷貝
IOUtil
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
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){
System.out.print(Integer.toHexString(b)+" ");
if (i++%10 == 0){
System.out.println();
}
}
//關閉輸入流
in.close();
}
public static void printHexByByteArray(String fileName)throws IOException{
FileInputStream in = new FileInputStream(fileName);
byte [] buf = new byte[20*1024];
//從in中批量讀取字節,放入到buf這個字節數組中,
// 從第0個位置開始放,最多放buf.length個,
//返回的是讀到的字節的個數
int bytes = in.read(buf,0,buf.length);//一次性讀完,說明字節數組足夠大
int j = 1;
for (int i = 0 ; i < bytes ; i++){
if (buf[i] <= 0xf){
System.out.print("0");
}
System.out.print(Integer.toHexString(buf[i])+" ");
if (j++%10 == 0){
System.out.println();
}
}
}
public static void copyFile(File srcFile,File desFile) throws IOException{
if (!srcFile.exists()){
throw new IllegalArgumentException("文件不存在");
}
if (!srcFile.isFile()){
throw new IllegalArgumentException(srcFile+"不是文件");
}
FileInputStream in = new FileInputStream(srcFile);//讀操作
FileOutputStream out = new FileOutputStream(desFile);//寫操作
byte [] buf = new byte[8];
int b = 0 ;
while(b != -1){
b = in.read(buf,0,buf.length);
System.out.print(b+" ");
out.write(buf,0,buf.length);
out.flush();//最好加上
}
in.close();
out.close();
}
}
IOUtilTest03
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtilTest03 {
public static void main(String[] args) {
try {
IOUtil.copyFile(new File("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat"),new File("D:\\IdeaProjects\\TestDemo\\demo\\NEWraf.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
輸出
8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 3 -1
字節流之數據輸入輸出流DataOutputString/DataInputStream
這一組操作類是對“流”的擴展,可以更加方便的讀取int,long/字符等類型數據。
DataOutputString中的方法舉例:writeInt() 、 writeDouble() 、writeUTF()
范例:DataOutputStream
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/19.
* 往一個文件里面寫數字,或者寫普通的數據類型
*/
public class DosDemo {
public static void main(String[] args) throws IOException{
String file = "demo/dos.dat";
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10l);
dos.writeDouble(10.5);
//采用UTF-8編碼寫出
dos.writeUTF("中國");
//采用UTF-16BE編碼寫出
dos.writeChars("中國");
dos.close();
IOUtil.printHex(file);
}
}
輸出
0 0 0 a ff ff ff f6 0 0
0 0 0 0 0 a 40 25 0 0
0 0 0 0 0 6 e4 b8 ad e5
9b bd 4e 2d 56 fd
范例:DataInputStream
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/19.
*/
public class DisDemo {
public static void main(String[] args) throws IOException{
String file = "demo/dos.dat";
IOUtil.printHex(file);
DataInputStream dis = new DataInputStream(new FileInputStream(file));
int i = dis.readInt();
System.out.println(i);
i = dis.readInt();
System.out.println(i);
long l = dis.readLong();
System.out.println(l);
double d = dis.readDouble();
System.out.println(d);
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
}
輸出
0 0 0 a ff ff ff f6 0 0
0 0 0 0 0 a 40 25 0 0
0 0 0 0 0 6 e4 b8 ad e5
9b bd 4e 2d 56 fd 10
-10
10
10.5
中國
字節緩沖流
字節緩沖流主要學習了解BufferedInputStream和BuferedOutputStream
這兩個流類為IO提供了帶緩沖區的操作,一般打開文件進行寫入或讀取操作時,都會加上緩沖,這種流模式主要提高了IO的輸入輸出性能。
從應用程序中把數據輸入放入文件,相當于將一缸水倒入到另一個缸中,其中:
FileOutputStream ---> write()方法相當于一滴一滴地把水“轉移”過去。
DataOutputStream ---> writeXxx()方法會方便一些,相當于一瓢一瓢的把水“轉移”過去。
BufferedOutputStream ---> write()方法更方便,相當于一瓢一瓢先放入桶中,再從桶中倒入到另一個缸中,提高了性能。
范例:修改IOUtil.java
增加方法:copyFileByBuffer
/**
* 進行文件的拷貝,使用帶緩沖的字節流
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{
if (!srcFile.exists()){
throw new IllegalArgumentException("文件不存在");
}
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();
}
范例:IOUtilTest04
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/19.
*/
public class IOUtilTest04 {
public static void main(String[] args) throws IOException {
IOUtil.copyFileByBuffer(new File("D:\\test.txt"),new File("D:\\test\\new_test.txt"));
}
}
輸出
之前的:
之后的:
字符流
字符流操作文本文件,如果是MP3,圖片,視頻之類的文件都采用字節流。
字符流的基本概念:
- 編碼問題
- 認識文本和文本文件:Java的文本(char)是16位無符號整數,是字符的unicode編碼(雙字節編碼)。文件是byte byte byte...的序列,文本文件是文本(char)序列按照某種編碼方案(utf-8、utf-16be、gbk)序列化為byte的存儲結構。
- 在Java里面的字符流也有讀(Reader抽象類),寫(Writer抽象類),字符的處理,一次處理一個字符,字符的底層仍然是基本的字節序列。
- Java中字符流的基本條件:
InputStreamReader 完成byte流解析為char流,按照編碼解析。
OutputStreamWriter 提供char流到byte流,按照編碼處理。
范例:對一個文件進行簡單的讀操作
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created by 99479 on 2017/7/20.
*/
public class IsrAndAOswDemo {
public static void main(String[] args) throws IOException{
FileInputStream in = new FileInputStream("D:\\test.txt");
InputStreamReader isr = new InputStreamReader(in,"utf-8");//項目的默認編碼
// int c ;
// while((c = isr.read()) != -1){
// System.out.print((char)c);
// }
char [] buffer = new char[8*1024];
int c;
//批量讀取,放入buffer這個字符數組,從第0個位置開始方式,最多放buffrt.length個
//返回的是讀到的個數
StringBuffer stringBuffer = new StringBuffer();
while ((c = isr.read(buffer,0,buffer.length)) != -1){
stringBuffer.append(buffer,0,buffer.length);
}
System.out.println(stringBuffer);
isr.close();//一定要注意關閉,注意關閉,注意關閉
}
}
輸出
客家話和;oh;一; 可不行了就回北京了黑戈壁厲害個i好吧;;iuh
;和哦哦哦回家oh;和
字符流的基本概念:
1. 編碼問題
- 認識文本和文本文
字符流的另一組操作類:
寫文件:FileWriter
寫文件:FileReader
剛剛做的字符流的讀寫操作類(InputStreamReader、OutputStreamReader)使用時嵌套了一個類,如果使用FileWriter、FileReader就很方便了。
范例:做讀寫操作
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/20.
*/
public class FrAndFwDemo {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("D:\\test.txt");
FileWriter fw = new FileWriter("D:\\test\\new_test.txt");
char [] buffer = new char[1024];
int c;
while((c = fr.read(buffer,0,buffer.length)) != -1){
fw.write(buffer,0,buffer.length);
fw.flush();
}
//注意關閉,注意關閉,注意關閉
fr.close();
fw.close();
}
}
字符流的過濾器
我們可以對字符流加過濾器,讓字符流有更多的功能,常用的有一組:
BufferedReader,它最強大的功能有一個是 ---> readLine 一次讀一行。
BufferedWriter/PrintWriter: ---> 寫一行。
范例:
import java.io.*;
/**
* Created by 99479 on 2017/7/20.
*/
public class BrAndBwOrPwDemo {
public static void main(String[] args) throws IOException{
//對文件進行讀寫操作
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\test.txt")));
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\test\\new_test.txt")));
PrintWriter pw = new PrintWriter("D:\\test\\new_test.txt");
String line;
while((line = br.readLine()) != null){//讀一行
System.out.println(line);//一次讀一行,并不能識別換行
// bw.write(line);
// bw.newLine();//換行操作
// bw.flush();
pw.println(line);
pw.flush();
}
br.close();
// bw.close();
pw.close();
}
}