java-IO编程
參考:https://juejin.im/post/6844903975326580749#heading-8
----------------------------------------------------------------------------------------------------------------------
IO流是一種順序讀寫的模式,單向流動並且以byte為最小字元
如果字符不是ASCLL碼,JAVA還提供了以下解決方案
reader、writer表示字符
最小單位是char
輸出的byte取決於編碼
reader、writer本質上是自動編碼的InputStream/OutputStream
使用reader雖然讀入的是一串字串,但是數據是char的字元
使用InputStream讀入的一樣是byte字元,但是可以根據編碼將二進制byte數組轉換成字串達到跟reader一樣的效果
當來源不是文本時使用InputStream比較快,而是文本時則使用reader比較方便
同步IO以及異步IO
同步IO
編寫時等待數據返回才執行後續
代碼編寫簡單,cpu效率低下
異步IO
讀寫時IO發出請求然後立刻執行後續代碼
代碼複雜,cpu效率提升
JDK提供的Java.io是同步IO Java.nio是異步IO
java.io.File表示文件系統的一個文件或者目錄創造方式,可以是相對路徑或者是絕對路徑
File f=new File("c:\\win\\note.exe");
getPath() //獲取路徑 String
getAbsolutePath() //獲取絕對路徑 String
getCanonicalPath()//獲取規範路徑 String
isFile() //判斷是否是文件 boolean
isDirectory() //判斷是否是路徑 boolean
canRead() //判斷是否可讀 boolean => setReadable(boolean readable)
canWrite() //判斷是否可寫 boolean
canExecute() //判斷是否可執行 boolean
length() //獲得文件大小
createNewFile() //建立一個新文件 File FileName = new File(FilePath); 也可建立
static createTempFile() //創造一個臨時文件
delete() //刪除文件
deleteOnExit() //在JVM退出時刪除該文件
list() //列出目錄下的文件和子目錄名稱 String[]
listFiles() //列出目錄下的文件和子目錄名稱 File[]
listFiles(FileFilter filter) //列出目錄下的文件和子目錄名稱 File[]
listFiles(FilenameFilter filter) //列出目錄下的文件和子目錄名稱 String[]
mkdir() //創造該目錄
mkdirs() //創造該目錄,必要時連父目錄都建造
delete() //刪除該目錄
讀取InputStream所有字元
InputStream input = new FileInputStream("C:\\Users\\user\\Desktop\\game.txt");
int n;
while ((n = input.read()) != -1) {
System.out.print((char)n);
}
在遇到問題時,會關閉input,而到了JDK1.7以後的版本finally的部分可以不用寫也會自動關閉。
InputStream input = null;
try {
input = new FileInputStream("C:\\Users\\user\\Desktop\\game.txt");
int n;
while ((n = input.read()) != -1) {
System.out.print((char)n);
}
}finally
{
if (input != null) input.close();
}
ByteArrayInputStream 可以在內存中模擬一個InputStream 常常用於測試
byte[] b = {S , A , B , C};
try(InputStream input = new ByteArrayInputStream(b)) {
int n;
while ((n = input.read()) != -1) {
System.out.print((char)n);
}
OutputStream 輸出文件
InputStream input = null;
try {
input = new FileInputStream("C:\\Users\\user\\Desktop\\game.txt");
OutputStream output = new FileOutputStream("C:\\Users\\user\\Desktop\\gameout.txt");
int n;
while ((n = input.read()) != -1) {
System.out.print((char)n);
output.write(n);
}
}finally {}
Filter模式 又稱 Decorator模式
以FileInputStream()為例,在FileInputStream上增加功能的做法
要添加緩衝功能需要 BufferedFileInputStream extends FileInputStream這樣擴展非常的麻煩。
因此有了Filter的模式
JDK中Filter分為兩類
一種為提供資料類,一種為附加功能類
提供資料 FileInputStream, ByteArrayInputStream
附加功能 BufferedInputStream, DigestInputStream
使用方法為
InputStream input = new GZIPInputStream(new BufferedInputStream (
new FileInputStream("test.gz")));
上述方法經過兩層包裝,但是不論經過幾層包裝,依然可以轉回FileInputStream類
上圖為InputStream的繼承樹
InputStream的作用為封裝其他的輸入流,並為他們提供額外功能。
常用的有BufferedInputStream和DataInputStream
一邊提供數據的實現類,一邊提供附加功能的實現類
提供數據的實現類不能進行同類包裝,附加功能類的可以
import java.io.*;
import java.util.zip.GZIPInputStream;
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream input = new CountInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream("test.txt.gz"))))) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int n;
while ((n = input.read(buffer)) != -1) {
output.write(buffer, 0, n);
}
byte[] data = output.toByteArray();
String text = new String(data, "UTF-8");
// 打印内容
//System.out.println(text);
//由于我们要使用count方法,因此要将InputStream类型向下转型为CountInputStream,因为我们明确的知道继承关系这里可以不判断是否可以安全的向下转型
System.out.println(InputStream.class.isAssignableFrom(CountInputStream.class));
System.out.println(((CountInputStream) input).count);
}
}
}
class CountInputStream extends FilterInputStream {
int count=0;
public CountInputStream(InputStream in) {
super(in);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
//通过调用父类的read方法获取包装的inputStream的字节长度
int n = super.read(b, off, len);
count +=n;
return n;
}
}
解決中文輸出問題
try {
input = new FileInputStream("C:\\Users\\user\\Desktop\\game.txt");
OutputStream output = new FileOutputStream("C:\\Users\\user\\Desktop\\gameout.txt");
int n;
byte[] b = new byte[100]; //加上這幾條
while ((n = input.read(b)) != -1) { //加上這幾條
String str = new String(b); //加上這幾條
System.out.print(str);
output.write(n);
}output.close();
}finally {}
中文輸出產生亂碼的原因是因為編碼問題,有些中文字是用兩個char編成,有些好像是三個,要看各編碼之間的差異,而上面的做法是產生一個buffer區,一次抓寫定位數的byte近來之後依次轉成string輸出,一來比較快,二來可以有效的阻止錯誤編碼的問題。
操作zip
ZipInputStream繼承FlatInputStream實現了ZipConstants接口
雖然ZipInputStream是FlatInputStream的子類,但是有些方法是ZipInputStream獨有的,使用這些的時候不能向上兼容。
ZipInputStream 可以讀取zip流 JarInputStream 提供了讀取jar的能力
classpath
可以讀取任意類型的文件
用classpath可以避免文件中的路徑太過依賴
class可以用getResourceAsStream() 可以從classpath獲取資源
需要檢查InputStream 是否為null
InputStream input = UploadServicesImpl.class.getResourceAsStream("\\game.txt");
try {
OutputStream output = new FileOutputStream("C:\\Users\\user\\Desktop\\gameout.txt");
if (input != null) {
//input = new FileInputStream("C:\\Users\\user\\Desktop\\game.txt");
int n;
byte[] b = new byte[100];
while ((n = input.read(b)) != -1) {
String str = new String(b);
System.out.print(str);
output.write(b);
}
}output.close();
序列化 就是把一個java對象變成byte[] 為了實現Java序列化,必須實現Serializable接口,反序列化則是指把一個byte[]內容變成Java對象 使用ObjectOutputStream和ObjectInputStream實現序列化跟反序列化。
readObject()可能拋出的異常
ClassNotFoundException 沒有找到對應的class
InvalidClassException Class 不匹配
反序列化可由JVM直接構造出Java對象。
可設置 serialVersionUID作為版本號(非必要)
Reader和InputStream的區別
int read(byte[]) InputStream
int read(char[]) Reader
FileReader 從文件讀取
CharArrayReader 從char[]組數讀取 可以模擬一個Reader
Char[] data = {'d' ,'c' ,'b' ,'A'}
Reader input = new CharArrayReader(data);
//Reader 讀取
Reader input = new FileReader("game.txt");
try {
if (input != null) {
int n;
char[] c = new char[100];
while ((n = input.read(c)) != -1) {
String str = new String(c);
System.out.print(str);
}
}output.close();
}finally {}
Reader與InputStream的關係
Reader是基於InputStream的構造,任何InputStream都可指定編碼並通過InputStreamReader轉換成Reader
Reader read = new InputStreamReader(new FileInputStream(File) , "UTF-8");
Writer 與 OutputStream的差距
write(int c)寫下一個字元
write(char[] c) 寫下char[] c的所有字元
write(char[] c , int off , int len) 寫入指定範圍的字元
write(String s)寫入String
FileWriter() 寫入文件
CharArrayWriter 寫入char[] 模擬Writer
//Reader 讀取
Reader input = new FileReader("game.txt");
try {
Writer writer = new FileWriter("gameout112.txt");
if (input != null) {
int n;
char[] c = new char[100];
while ((n = input.read(c)) != -1) {
String str = new String(c);
System.out.print(str);
writer.write(c);
}
}writer.close();
}finally {}
唯一搞不懂的是不知道為什麼,他會建立在桌面....
留言
張貼留言