JavaSE-IO流
I/O流,輸入/輸出流。數據在設備間的傳輸稱為流,IO流就是用來處理設備間數據傳輸問題的。
常見應用場景(文件復制,文件上傳,文件下載)
Java中流分為字節流和字符流,又細分為字節輸入流(Reader),字節輸出流(Writer),字符輸入流(InputStream),字符輸出流(OutputStream)
字節流
字節流抽象基類:
InputStream:這個抽象類是表示字節輸入流所有類的超類(讀數據)
OutputStream:這個抽象類是表示字節輸出流所有類的超類(寫數據)
FileOutputStream
構造方法
FileOutputStream(String name) 創建文件輸出流以指定的名稱寫入文件, 用於寫入諸如圖像數據之類的原始字節的流
FileOutputStream(File file) 創建文件輸出流以指定的文件對象寫入文件File file = new File("src");
FileOutputStream fos = new FileOutputStream(file);
等價於
FileOutputStream fos = new FileOutputStream(new File("src"));
public static void main(String[] args) throws IOException {
//創建字節輸出流對象: 1、調用系統api創建了文件 2、創建字節輸出流對象 3、讓字節輸出流對象指向創建好的文件
FileOutputStream fileOutputStream = new FileOutputStream("/Users/b/Desktop/java1.txt");
// void write(int b)
// 將指定字節寫入此文件輸出流。
fileOutputStream.write(97); //根據ascii表對應字符
fileOutputStream.close(); //1、釋放相關資源,2、關閉此輸出流
}
字節輸出流寫數據的三種方式
void write(byte[] b) 將 b.length 個字節從指定 byte 數組寫入此文件輸出流中。
void write(byte[] b, int off, int len) 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此文件輸出流。
void write(int b) 將指定字節寫入此文件輸出流。
public class FileOutputStreamDemo02 {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("/Users/b/Desktop/java1.txt");
// void write(int b) 將指定字節寫入此文件輸出流。
fileOutputStream.write(97);
fileOutputStream.write(98);
fileOutputStream.write(99);
fileOutputStream.write(100);
fileOutputStream.write(101);
//void write(byte[] b) 將 b.length 個字節從指定 byte 數組寫入此文件輸出流中。
byte[] b = {102, 103, 104, 105, 106}; // f g h i j
fileOutputStream.write(b);
//void write(byte[] b, int off, int len) 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此文件輸出流。
byte[] c = {107, 108, 109, 110, 111}; //k l m n o
fileOutputStream.write(c, 1, 3); //這里偏移量為1,即跳過k,從l開始寫,len為3,即寫入3個字節也就是lmn 沒有 o
}
}
String <=> Byte
tring str = "string";
byte[] bytes = str.getBytes();
for (int b1 : bytes
) {
System.out.println(b1);
}
追加寫入
public FileOutputStream(String name, boolean append) throws FileNotFoundException
創建一個向具有指定 name
的文件中寫入數據的輸出文件流。如果第二個參數為 true
,則將字節寫入文件末尾處,而不是寫入文件開始處。
FileOutputStream fos1 = new FileOutputStream("/Users/b/Desktop/java1.txt", true);
//append:true ,此時為追加寫入的字節輸出流
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("/Users/b/Desktop/java1.txt");
FileOutputStream fos1 = new FileOutputStream("/Users/b/Desktop/java1.txt", true);
for (int i = 0; i < 10; i++) {
fileOutputStream.write("Hello".getBytes());
fileOutputStream.write("\n".getBytes());
}
fileOutputStream.close();
for (int i = 0; i < 10; i++) {
fos1.write("World".getBytes());
fos1.write("\r".getBytes());
}
fos1.close();
}
異常捕獲
public class FileOutpuStreamExcept {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("/Users/b/Desktop/java1.txt");
fos.write("Exception".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
readFile&writeFile
import java.io.*;
public class ByteStreamTestDemo {
public static void main(String[] args) {
ByteStreamTestDemo bstd = new ByteStreamTestDemo();
String inputstr = bstd.readFile("/Users/b/Desktop/image1.txt");
System.out.println(inputstr);
bstd.writeFile("/Users/b/Desktop/image1.txt", "Hello Java");
}
public String readFile(String path) {
FileInputStream fis = null;// 實例化FileInputStream對象;
String str = null;
try {
// 1.根據path路徑實例化一個輸入流的對象
fis = new FileInputStream(path);
//2. 返回這個輸入流中可以被讀的剩下的bytes字節的估計值;
int size = fis.available();
//3. 根據輸入流中的字節數創建byte數組;
byte[] array = new byte[size];
fis.read(array);//4.把數據讀取到數組中;
//5.根據獲取到的Byte數組新建一個字符串,然后輸出;
str = new String(array);
System.out.println(str);//輸出;
} catch( FileNotFoundException e) {
// 解決new FileInputStream(path);可能會發生的異常;
e.printStackTrace();
} catch (IOException e) {
// 解決fis.available()時可能發生的異常;
e.printStackTrace();
} finally {
//6.在最后,關閉我們的IO流
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return str;
}
public void writeFile(String path, String content) {
FileOutputStream fos = null;
try {
//1.根據文件路徑創建輸出流
fos = new FileOutputStream(path);
//2.把string轉換為byte數組;
byte[] array = content.getBytes();
//3.把byte數組輸出;
fos.write(array);
} catch (FileNotFoundException e) {
// 解決new FileOutputStream(path)出現的問題
e.printStackTrace();
} catch (IOException e) {
// 解決fos.write(array)可能會出現的問題;
e.printStackTrace();
} finally {
/*
* 在方法的最后一定實現這個方法;
*/
try {//4.關閉IO流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream
FileInputStream.read()
int
read() 從此輸入流中讀取一個數據字節。 int
read(byte[] b)
從此輸入流中將最多b.length
個字節的數據讀入一個 byte 數組中。int
read(byte[] b, int off, int len)
從此輸入流中將最多len
個字節的數據讀入一個 byte 數組中。
FileInputStream.read()
public static void main(String[] args) throws IOException {
//創建讀數據對象
FileInputStream fis = new FileInputStream("/Users/b/Desktop/java1.txt");
//讀取對象
int read = fis.read();
while(read != -1) {
System.out.println(read);
System.out.println((char)read);
read = fis.read();
}
//釋放資源
fis.close();
}
int by;
while((by = fis.read()) != -1) {
System.out.print((char)read);
}
復制字符流文件
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/b/Desktop/java1.txt");
FileOutputStream fos = new FileOutputStream("/Users/b/Desktop/java2.txt");
int by;
while ((by = fis.read()) != -1) {
fos.write((char)by);
}
fis.close();
fos.close();
}
復制Byte流文件
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/b/Desktop/Images/image-2.png");
FileOutputStream fos = new FileOutputStream("/Users/b/Desktop/image1.png");
byte[] b = new byte[1024];
int len;
while ((len = fis.read(b)) != -1){
fos.write(b);
}
fis.close();
fos.close();
}
讀取內容方法
int read() 從此輸入流中讀取一個數據字節。 int read(byte[] b) 從此輸入流中將最多 b.length 個字節的數據讀入一個 byte 數組中。 int read(byte[] b, int off, int len) 從此輸入流中將最多 len 個字節的數據讀入一個 byte 數組中。 參數為內容存入的byte數組,返回值為該數組的長度或者說數據元素的個數,如果已到達文件末尾,則返回 -1。
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/b/Desktop/java2.txt");
byte[] bys = new byte[1024];// 這里通常放1024及其整數倍的數據
int len;
while((len = fis.read(bys)) != -1){
System.out.println(len);
System.out.print(new String(bys, 0, len));
}
fis.close();
}
String <=> Byte 編碼轉換
String -> Byte byte[] getBytes() 使用默認字符集將String轉換為Byte存儲在數組內 byte[] getBytes(String charsetName) 使用指定的字符集將該String編碼為Byte存儲在數組內
Byte -> String String(byte[] bytes) 使用默認字符集將Byte轉換為String String(byte[] bytes, String CharsetName) 使用指定字符集將Byte轉換為String
public static void main(String[] args) {
//String => Byte,默認UTF-8
String s = "zh1z3ven";
byte[] bytes = s.getBytes();
System.out.println(bytes);
for (int i : bytes
) {
System.out.println(i);
}
System.out.println(Arrays.toString(bytes));
//Byte => String
byte[] b = {97, 98, 99, 100, 101, 102};
String str = new String(b);
System.out.println(str);
}
字符流
字符流抽象基類
字符流處理的是字符數據,而字節流處理的是byte數據
Witer 字符輸出流抽象基類
Reader 字符輸入流抽象基類
對應的子類為
OutputStreamWriter 使用指定的Charset將字符編碼為字節,從字符流到字節流的橋梁
InputStreamReader 讀取字節,用指定的Charset將字節編碼為字符,從字節流到字符流的橋梁
這兩個類的優點就是可以處理不同字符集的流
如果都是默認字符集或者字符集一樣的話可以使用 FileReader
和FileWriter
public static void main(String[] args) throws IOException {
File f = new File("/Users/b/Desktop/image1.txt");
f.createNewFile();
FileOutputStream fos = new FileOutputStream(f);
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write("zh1z3ven");
osw.close();
FileInputStream fis = new FileInputStream(f);
InputStreamReader isr = new InputStreamReader(fis);
int len;
while ((len = isr.read()) != -1) {
System.out.println(len);
System.out.println((char)len);
}
isr.close();
}
OutputStreamWriter
void write(int c) 寫入一個字符 void write(char[] cbuf) 寫入一個字符數組 void write(char[] cbuf, int off, int len) 寫入一個根據cbuf,以off為偏移量,長度為len的字符數組的一部分 void write(String str) 寫入一個字符串 void write(String str, int off, int len) 寫入字符串的一部分
void write()
public static void main(String[] args) throws IOException{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/Users/b/Desktop/image1.txt"));
osw.write(97);
char[] cbuf = {'c', 'v', 'b', 'n', 'm'};
osw.write(cbuf);
osw.write(cbuf, 1, 4);
String str = "zh1z3ven";
osw.write(str);
osw.write(str, 2, 3);
osw.flush();
osw.close();
}
InputStreamReader
int read() 一次讀一個字符,返回字符對應的ascii值
int read(char[] buf) 一次讀一個字符數組
int read()
public static void main(String[] args) throws IOException{
InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/b/Desktop/image1.txt"));
//int read() 讀取文件
int ch;
while ((ch = isr.read()) != -1){
System.out.print((char)ch);
}
isr.close();
}
int read(char[] buf)
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException{
InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/b/Desktop/image1.txt"));
//int read(char[] buf) 讀取文件
char[] ch = new char[1024]; //以char數組接受文件內容
int len; //存儲char數組長度
while((len = isr.read(ch)) != -1){
String str = new String(ch, 0, len); //將char轉為String
System.out.print(str);
}
isr.close();
}
}
字符流復制文件
最明顯的一點就是不需要再進行Byte<=>String
的轉換了
0x01 一次讀寫一個數據
public static void main(String[] args) throws IOException{
FileInputStream fis = new FileInputStream("/Users/b/Desktop/java2.txt");
InputStreamReader isr = new InputStreamReader(fis);
FileOutputStream fos = new FileOutputStream("/Users/b/Desktop/java4.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
int ch;
while((ch = isr.read()) != -1){
osw.write(ch);
}
}
0x02 一次讀取一個字符數組
public static void main(String[] args) throws IOException {
//OutpuStreamWriter.write(String str) + InputStreamReader().read()
FileInputStream fis = new FileInputStream("/Users/b/Desktop/java2.txt");
InputStreamReader isr = new InputStreamReader(fis);
char[] chars = new char[1024];
isr.read(chars);
String str = new String(chars);
FileOutputStream fos = new FileOutputStream("/Users/b/Desktop/java3.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
// String str = "琥珀色黃昏像風在很美的遠方" + "\n" + "你的臉沒有化妝我卻瘋狂愛上";
osw.write(str);
System.out.println(str);
isr.close();
osw.close();
}
FileReader
用於讀取字符文件的便捷類
繼承自InputStreamReader類,即可一次讀一個字符或一次讀一個字符數組
FileReader(String fileName)
FileWriter
用於寫入字符文件的便捷類
繼承自OutputWriter類
FileWriter(String fileName)
FileReader&FileWriter讀寫復制文件
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("/Users/b/Desktop/java2.txt");
FileWriter fileWriter = new FileWriter("/Users/b/Desktop/java6.txt");
char[] chars = new char[1024];
int len;
while((len = fileReader.read(chars)) != -1){
fileWriter.write(chars, 0 ,len);
}
fileReader.close();
fileWriter.close();
}
可以簡單理解為簡化了InputStreamReader和OutputStreamWriter新建字符流對象的過程。
但是不可以處理不同字符集的數據流。
字符緩沖流
BufferedReader
從字符輸入流中讀取文本,緩沖各個字符,從而實現字符、數組和行的高效讀取。
可以指定緩沖區的大小,或者可使用默認的大小。大多數情況下,默認值就足夠大了。
主要用到的還是read方法
int read(char c) int read(char[] cbuf, int off, int len) String readLine() 讀取一個文本行
BufferedWriter
將文本寫入字符輸出流,緩沖各個字符,從而提供單個字符、數組和字符串的高效寫入。
可以指定緩沖區的大小,或者接受默認的大小。在大多數情況下,默認值就足夠大了。
主要用到的還是write方法
void newLine() 寫入一個行分隔符。 void write(char[] cbuf, int off, int len) 寫入字符數組的某一部分。 void write(int c) 寫入單個字符。 void write(String s, int off, int len) 寫入字符串的某一部分。
復制文件操作
BufferedReader br = new BufferedReader(new FileReader("/Users/b/Desktop/java2.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("/Users/b/Desktop/java7.txt"));
//一次讀取一個字符
int ch;
while ((ch = br.read()) != -1){
bw.write((char) ch);
}
br.close();
bw.close();
BufferedReader br = new BufferedReader(new FileReader("/Users/b/Desktop/java2.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("/Users/b/Desktop/java7.txt"));
//一次讀取一個字符數組
int len;
char[] chars = new char[1024];
while ((len = br.read(chars)) != -1){
bw.write(chars, 0 ,len);
}
bw.flush();
br.close();
bw.close();
readLine()與newLine()
一般使用字節緩沖流一次讀取一個字節數組的方式讀取文件
void newLine() 寫入一個行分隔符。自動根據系統而定
String readLine() 讀取一個文本行(不包含換行符)。當讀到null時,證明已讀完此文件
write()
newLine()
flush()
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new FileReader("/Users/b/Desktop/java2.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("/Users/b/Desktop/java8.txt"));
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
標准輸入流
InputStream
InputStream -> InputStreamReader -> BufferedReader
將標准輸入流轉換為字符緩沖輸入流處理
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
獲取一行鍵盤輸入,是Scanner類的底層
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("請輸入字符串:");
String line = br.readLine();
System.out.println("你輸入的字符串是:" + line);
System.out.print("請輸入一個整數:");
int len = Integer.parseInt(br.readLine()); // 將字符串=>整型
System.out.println("你輸入的數是:" + len);
}
PrintStream
PrintStream ps = Systm.out
常見的方法有 println,print
字節打印流
序列化與反序列化
對象序列化,就是將對象變成一個字節序列保存在磁盤或者在網絡中傳輸對象。
對象反序列化,就是將序列化對象的字節序列進行反序列化重構對象。
序列化流:ObjectOutputStream
反序列化流:ObjectInputStream
ObjectOutputStream
void writeObject(OutputStream out)
public static void main(String[] args) throws IOException {
//構造方法: ObjectOutputStream(OutputStream out)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/b/Desktop/java10.txt"));
Student zh1z3ven = new Student("zh1z3ven", 21);
//void wirteObject(Object obj);將指定對象(該對象需要implements Serializable)寫入流中,最后保存在文件內
oos.writeObject(zh1z3ven);
//釋放資源
oos.close();
}
ObejctInputStream
public static void main(String[] args) throws IOException, ClassNotFoundException {
//創建ObjectinputStream對象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/b/Desktop/java10.txt"));
//readObject()反序列化
Object obj = ois.readObject();
//向下轉型
Student s = (Student) obj;
System.out.println("Name: " + s.getName() + " Age: " + s.getAge());
//釋放資源
ois.close();
}
反序列化時可能存在的問題
1、假如我們在一個類序列化后去修改了它的類文件,在進行反序列化讀取對象時可能會出現問題會拋出如下異常
java.io.InvalidClassException
因為類的串行版本與從流中讀取出來的不一致而導致的
2、java強烈建議需要序列化的類 定義一個serialVersionUID
private static final long serialVersionUID = 42L
顯示定義串行版本的UID值
3、有transient修飾符修飾的變量並不會被序列化