Java輸入流與輸出流超全面講解
一、輸入流與輸出流的定義及作用
定義
輸入流(Input Stream):在 Java 世界里,輸入流是一種機(jī)制,它負(fù)責(zé)從外部世界(像硬盤(pán)文件系統(tǒng)、網(wǎng)絡(luò)連接、內(nèi)存數(shù)組等數(shù)據(jù)源)讀取數(shù)據(jù)到程序內(nèi)部。
輸出流(Output Stream):輸出流則是將程序里的數(shù)據(jù)輸出到外部世界,外部世界可以是文件、網(wǎng)絡(luò)連接等目標(biāo)位置。
作用
輸入流和輸出流是 Java 實(shí)現(xiàn)數(shù)據(jù)輸入輸出操作的核心,它們搭建起了程序與外部環(huán)境之間的數(shù)據(jù)交互橋梁,使得程序能夠讀取外部數(shù)據(jù)進(jìn)行處理,也能將處理結(jié)果輸出到外部。
比如說(shuō)把控制臺(tái)的數(shù)據(jù)讀入到程序當(dāng)中?;蛘哒f(shuō)把程序當(dāng)中的數(shù)據(jù)輸出到控制臺(tái)
import java.io.IOException;
public class ReadByteByByte {
public static void main(String[] args) {
try {
System.out.println("請(qǐng)輸入一些內(nèi)容:");
int input;
while ((input = System.in.read()) != -1) {
System.out.print((char) input);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}二、輸入流和輸出流最基礎(chǔ)的類及方法使用
基礎(chǔ)類
Java 中,InputStream 和 OutputStream 分別是輸入流和輸出流的最基礎(chǔ)抽象類。它們以字節(jié)作為讀取和寫(xiě)入數(shù)據(jù)的基本單元。
常用方法及使用示例
InputStream 類
int read():該方法從輸入流中讀取一個(gè)字節(jié)的數(shù)據(jù),返回值是該字節(jié)對(duì)應(yīng)的整數(shù)(范圍為 0 - 255)。當(dāng)?shù)竭_(dá)流的末尾時(shí),返回 -1。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamExample {
public static void main(String[] args) {
try (InputStream is = new FileInputStream("input.txt")) {
int byteData;
while ((byteData = is.read()) != -1) {
System.out.print((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}int read(byte[] b):嘗試將最多b.length個(gè)字節(jié)的數(shù)據(jù)讀入到字節(jié)數(shù)組b中,返回實(shí)際讀取的字節(jié)數(shù)。若到達(dá)流末尾,返回 -1。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamReadArrayExample {
public static void main(String[] args) {
try (InputStream is = new FileInputStream("input.txt")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
for (int i = 0; i < bytesRead; i++) {
System.out.print((char) buffer[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}OutputStream 類
void write(int b):將指定的字節(jié)寫(xiě)入輸出流。這里的參數(shù)b雖然是int類型,但實(shí)際上只使用低 8 位。import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class OutputStreamExample { public static void main(String[] args) { try (OutputStream os = new FileOutputStream("output.txt")) { String data = "Hello, World!"; for (int i = 0; i < data.length(); i++) { os.write(data.charAt(i)); } } catch (IOException e) { e.printStackTrace(); } } }void write(byte[] b):將字節(jié)數(shù)組b中的所有字節(jié)寫(xiě)入輸出流。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamWriteArrayExample {
public static void main(String[] args) {
try (OutputStream os = new FileOutputStream("output.txt")) {
String data = "Hello, Java!";
byte[] buffer = data.getBytes();
os.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}三、能否以其他單位進(jìn)行讀取
雖然 InputStream 和 OutputStream 以字節(jié)為基礎(chǔ)單位進(jìn)行讀取和寫(xiě)入,但 Java 也提供了以其他單位進(jìn)行操作的方式:
字符
可以使用字符流來(lái)以字符為單位進(jìn)行讀取和寫(xiě)入。字符流基于字節(jié)流構(gòu)建,會(huì)自動(dòng)處理字符的編碼和解碼。例如 Reader 和 Writer 是字符流的抽象基類,FileReader 和 FileWriter 是具體實(shí)現(xiàn)類。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CharacterStreamExample {
public static void main(String[] args) {
try (FileReader fr = new FileReader("input.txt");
FileWriter fw = new FileWriter("output.txt")) {
int charData;
while ((charData = fr.read()) != -1) {
fw.write(charData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}數(shù)字和對(duì)象
對(duì)于數(shù)字和對(duì)象,可以使用數(shù)據(jù)流和對(duì)象流。
數(shù)據(jù)流:
DataInputStream和DataOutputStream可以方便地讀寫(xiě)基本數(shù)據(jù)類型(如int、double等)。
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamExample {
public static void main(String[] args) {
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"));
DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"))) {
dos.writeInt(123);
int num = dis.readInt();
System.out.println(num);
} catch (IOException e) {
e.printStackTrace();
}
}
}對(duì)象流:
ObjectInputStream和ObjectOutputStream用于讀寫(xiě) Java 對(duì)象。對(duì)象需要實(shí)現(xiàn)Serializable接口才能進(jìn)行序列化和反序列化。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class ObjectStreamExample {
public static void main(String[] args) {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
Person person = new Person("John", 30);
oos.writeObject(person);
Person readPerson = (Person) ois.readObject();
System.out.println("Name: " + readPerson.getName() + ", Age: " + readPerson.getAge());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}四、字符流、對(duì)象流等與字節(jié)流的關(guān)系
字符流、對(duì)象流、數(shù)據(jù)流等都與字節(jié)流密切相關(guān),它們是在字節(jié)流的基礎(chǔ)上構(gòu)建起來(lái)的。
字符流:在字節(jié)流的基礎(chǔ)上添加了字符編碼協(xié)議。在讀取數(shù)據(jù)時(shí),根據(jù)編碼協(xié)議讀取指定數(shù)量的字節(jié),然后進(jìn)行解碼得到對(duì)應(yīng)的字符;在寫(xiě)入數(shù)據(jù)時(shí),將字符編碼為字節(jié)后通過(guò)字節(jié)流輸出。
對(duì)象流:輸入時(shí)先獲取對(duì)象的序列化結(jié)果(字節(jié)流),然后使用字節(jié)流讀取,再進(jìn)行反序列化得到對(duì)象;輸出時(shí)將對(duì)象進(jìn)行序列化得到字節(jié)流,然后使用字節(jié)流將字節(jié)流傳輸出去。
數(shù)據(jù)流:同樣是在字節(jié)流的基礎(chǔ)上,提供了讀寫(xiě)基本數(shù)據(jù)類型的功能,會(huì)將基本數(shù)據(jù)類型轉(zhuǎn)換為字節(jié)進(jìn)行讀寫(xiě)。
綜上所述,字節(jié)流是 Java 輸入輸出流體系的基礎(chǔ),其他類型的流都是為了滿足不同的數(shù)據(jù)處理需求而在字節(jié)流基礎(chǔ)上進(jìn)行的擴(kuò)展。
五、Buffered 輸入流實(shí)現(xiàn)更快讀取效率的原理
我看FIleInputStream每次讀數(shù)據(jù)都要調(diào)用本地方法read0,如果碰到大文件頻繁調(diào)用,可能導(dǎo)致效率會(huì)比較低,有什么更好的方法嗎?
在 Java 中,像 BufferedInputStream 和 BufferedReader 這類帶有緩沖區(qū)(Buffer)的輸入流能夠提升讀取效率,其核心原理在于減少系統(tǒng)調(diào)用的次數(shù)。以下是具體的解釋:
系統(tǒng)調(diào)用開(kāi)銷
系統(tǒng)調(diào)用是指程序向操作系統(tǒng)內(nèi)核請(qǐng)求服務(wù)的過(guò)程,例如從磁盤(pán)、網(wǎng)絡(luò)或控制臺(tái)讀取數(shù)據(jù)。每次進(jìn)行系統(tǒng)調(diào)用都需要進(jìn)行上下文切換,也就是從用戶態(tài)切換到內(nèi)核態(tài),這個(gè)過(guò)程會(huì)消耗大量的時(shí)間和資源。如果每次只讀取少量的數(shù)據(jù),就會(huì)頻繁地進(jìn)行系統(tǒng)調(diào)用,從而導(dǎo)致效率低下。
緩沖區(qū)的作用
帶有緩沖區(qū)的輸入流在內(nèi)部維護(hù)了一個(gè)緩沖區(qū)(通常是一個(gè)字節(jié)數(shù)組或字符數(shù)組)。當(dāng)程序第一次調(diào)用讀取方法時(shí),它會(huì)進(jìn)行一次系統(tǒng)調(diào)用,從數(shù)據(jù)源(如文件、網(wǎng)絡(luò)等)中讀取一大塊數(shù)據(jù)到緩沖區(qū)中。之后,程序再進(jìn)行讀取操作時(shí),會(huì)先從緩沖區(qū)中獲取數(shù)據(jù),而不是直接進(jìn)行系統(tǒng)調(diào)用。只有當(dāng)緩沖區(qū)中的數(shù)據(jù)被讀完后,才會(huì)再次進(jìn)行系統(tǒng)調(diào)用,讀取新的數(shù)據(jù)到緩沖區(qū)。
例如,BufferedInputStream 會(huì)一次性從底層輸入流(如 FileInputStream)中讀取多個(gè)字節(jié)到其內(nèi)部的字節(jié)數(shù)組緩沖區(qū),后續(xù)的讀取操作就可以直接從這個(gè)緩沖區(qū)獲取數(shù)據(jù),減少了與底層輸入源的交互次數(shù),從而提高了讀取效率。
Buffered 輸入流的使用方法
1. BufferedInputStream 的使用(處理字節(jié)流)
BufferedInputStream 用于處理字節(jié)流,以下是一個(gè)簡(jiǎn)單的示例,展示如何使用 BufferedInputStream 讀取文件:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class BufferedInputStreamExample {
public static void main(String[] args) {
try (InputStream fis = new FileInputStream("example.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
int byteData;
while ((byteData = bis.read()) != -1) {
System.out.print((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}在上述代碼中,首先創(chuàng)建了一個(gè) FileInputStream 用于從文件中讀取字節(jié)數(shù)據(jù),然后將其作為參數(shù)傳遞給 BufferedInputStream 的構(gòu)造函數(shù),創(chuàng)建一個(gè)帶有緩沖區(qū)的輸入流。之后,通過(guò) BufferedInputStream 的 read() 方法讀取數(shù)據(jù),它會(huì)先從緩沖區(qū)中獲取數(shù)據(jù),當(dāng)緩沖區(qū)為空時(shí)再進(jìn)行系統(tǒng)調(diào)用讀取新的數(shù)據(jù)。
2. BufferedReader 的使用(處理字符流)
BufferedReader 用于處理字符流,以下是一個(gè)使用 BufferedReader 讀取文件的示例:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}在這個(gè)示例中,創(chuàng)建了一個(gè) FileReader 用于從文件中讀取字符數(shù)據(jù),然后將其傳遞給 BufferedReader 的構(gòu)造函數(shù)。BufferedReader 會(huì)將字符數(shù)據(jù)讀取到其內(nèi)部的緩沖區(qū),通過(guò) readLine() 方法可以方便地按行讀取數(shù)據(jù),提高了讀取文本文件的效率。
通過(guò)使用帶有緩沖區(qū)的輸入流,可以顯著減少系統(tǒng)調(diào)用的次數(shù),從而提高數(shù)據(jù)讀取的效率。
總結(jié)
到此這篇關(guān)于Java輸入流與輸出流的文章就介紹到這了,更多相關(guān)Java輸入流與輸出流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot一個(gè)接口多個(gè)實(shí)現(xiàn)類的調(diào)用方式總結(jié)
這篇文章主要介紹了SpringBoot一個(gè)接口多個(gè)實(shí)現(xiàn)類的調(diào)用方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01
Java中json格式化BigDecimal保留2位小數(shù)
這篇文章主要給大家介紹了關(guān)于Java中json格式化BigDecimal保留2位小數(shù)的相關(guān)資料,BigDecimal是Java中的一個(gè)數(shù)學(xué)庫(kù),可以實(shí)現(xiàn)高精度計(jì)算,文中給出了詳細(xì)的代碼實(shí)例,需要的朋友可以參考下2023-09-09
maven項(xiàng)目pom.xml中parent標(biāo)簽的使用小結(jié)
使用maven是為了更好的幫項(xiàng)目管理包依賴,maven的核心就是pom.xml,當(dāng)我們需要引入一個(gè)jar包時(shí),在pom文件中加上就可以從倉(cāng)庫(kù)中依賴到相應(yīng)的jar包,本文就來(lái)介紹一下maven項(xiàng)目pom.xml中parent標(biāo)簽的使用小結(jié),感興趣的可以了解一下2023-12-12
java中的反射及其優(yōu)點(diǎn)說(shuō)明
這篇文章主要介紹了java中的反射及其優(yōu)點(diǎn)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Java?Chassis3應(yīng)用視角的配置管理技術(shù)解密
這篇文章主要為大家介紹了Java?Chassis3應(yīng)用視角的配置管理相關(guān)的機(jī)制和背后故事,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
SpringMVC+ZTree實(shí)現(xiàn)樹(shù)形菜單權(quán)限配置的方法
本篇文章主要介紹了SpringMVC+ZTree實(shí)現(xiàn)樹(shù)形菜單權(quán)限配置的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
SpringBoot整合多個(gè)Mq服務(wù)做法詳解
SpringBoot整合rabbitmq很容易,但是整合的目的是為了使用,那要使用rabbitmq就要對(duì)其有一定的了解,不然容易整成一團(tuán)漿糊。因?yàn)檎f(shuō)到底,SpringBoot只是在封裝rabbitmq的API,讓其更容易使用而已,廢話不多說(shuō),讓我們一起整它2023-02-02
Spring源碼之事件監(jiān)聽(tīng)機(jī)制詳解(@EventListener實(shí)現(xiàn)方式)
這篇文章主要介紹了Spring源碼之事件監(jiān)聽(tīng)機(jī)制(@EventListener實(shí)現(xiàn)方式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08

