目錄
2.3 緩衝區類(高效類):BufferedOutputStream,BufferedInputStream
3.1 字節流轉化爲字符流:OutputStreamWriter,InputStreamReader
3.2 OutputStreamWriter,InputStreamReader的封裝類(簡化寫法):FileWriter,FileReader
3.3 緩衝區類(高效類):BufferedWriter,BufferedReader
1.IO流的分類
1.1 通過流分類:輸入流,輸出流
輸入流:從接收器輸入到java程序。
輸出流:輸出流接受輸出字節並將這些字節發送到某個接收器,也就是從java程序輸出到接收器。
1.2 通過數據單位不同分分類:字符流,字節流
在java版本中是先有字節流,再有字符流,1字符 = 2字節
字節流:每次傳輸一個字節,一箇中文漢字是兩個字節,會出現亂碼。
字符流:每次傳輸兩個字節,一般傳輸中文
1.3 抽象類
字節輸出流:OutputStream
字節輸入流:InputStream
字符輸出流:Writer
字符輸入流:Reader
1.4 各抽象類的選用
選用輸入,輸出流通過需求選用
選用字符,還是字節,一般用記事本打開是看得懂的用字符,看不懂的用字符。字節流更加適用於音頻文件、圖片、歌曲。
2.文件流的使用
2.1 字節輸出流:FileOutputStream
向文件中寫入數據
public static void main(String[] args) throws IOException {
//追加寫入,append爲true追加
FileOutputStream fos = new FileOutputStream("E:\\b.txt",true);
byte[] b = {'a','b','c','d'};
fos.write(97);//底層是二進制數據,記事本會找到對應的字符值
fos.write("\n".getBytes());//加入換行,一般windows寫法是\r\n,linux是\n,mac是\r
fos.write("hello,world".getBytes());
fos.write("\n".getBytes());
fos.write(b,1,2);
fos.write("\n".getBytes());
fos.close();
}
程序分爲三部分:
(1)創建字節輸出流對象:這一步創建了文件,創建了fos對象,並把fos對象指向了此文件
(2)寫入數據
(3)釋放資源:釋放了文件所佔用的相關資源,變成垃圾,通知系統回收
異常處理方式:
異常有很多變形,這裏用try...catch...catch...finally...(這裏fos可能爲空,如當找不到指定的盤符是,或者說是我只有一個C盤,得到fos爲空)
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("E:\\b.txt",true);
fos.write("異常處理".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fos != null){//fos不爲空才執行,因爲finally是默認執行的
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.2 字節輸入流:FileInputStream
讀取文件:一次讀取一個字節:int read()
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("E:\\b.txt");
int by = 0;
//讀取,賦值,判斷
while((by=fis.read())!=-1){
System.out.print((char) by);
}
fis.close();
}
讀取文件如果沒有相應文件不會爲你創建文件,這裏用的 int read().一次傳輸一個字節,返回的是數據字節,當返回值爲-1,則表示傳輸結束,漢字是兩個字節,會被拆分,返回值的第一個字節都是負數,第二個字節可能是正數,也是合併的判斷依據
英文傳輸返回值:
[97, 98, 99, 100, 101, 102]
對應:abcdef
中文傳輸返回值:
[-26, -79, -119, -27, -83, -105, -26, -117, -122, -27, -120, -122, -28, -68, -96, -24, -66, -109]
對應:漢字拆分傳輸(UTF-8編碼表示字符最多佔三個字節)
一次讀取多個字節:public int read(byte[ ] b)
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("e:\\b.txt");
byte[] by = new byte[1024];
int len = 0;
while((len = fis.read(by))!=-1){
//避免讀出的數據不滿足數組大小
System.out.print(new String(by,0,len));
}
fis.close();
}
public int read(byte[ ] b):把讀取的數據存到數組b裏,返回值是實際讀取到的字節個數,如果緩衝區沒有了就返回-1
注意: 這裏by數組的長度一般是1024或者1024的整數倍
相對於一個字節的讀取快了1024倍或者1024的整數倍,傳輸視頻等大文件時使用
傳輸圖片練習代碼
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\圖片.jpeg");
FileOutputStream fos = new FileOutputStream("E:\\copy.jpeg");
byte[] by = new byte[1024];
int len = 0;
while((len = fis.read(by)) != -1){
fos.write(by,0,len);
}
fos.close();
fis.close();
}
2.3 緩衝區類(高效類):BufferedOutputStream,BufferedInputStream
緩衝區類類似於一個杯子,用來裝水(水是指OutputStream,InputStream),運行效率高,代碼體現:
//向文件寫入數據
public static void main(String[] args) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream("e:\\b.txt"));
bos.write("hello".getBytes());
bos.close();
}
//從文件讀取數據
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new
FileInputStream("e:\\b.txt"));
byte[] by = new byte[1024];
int len = 0;
while ((len = bis.read(by)) != -1){
System.out.println(new String(by,0,len));
}
bis.close();
}
3.轉換流的使用
3.1 可將字節流轉化爲字符流:OutputStreamWriter,InputStreamReader
由於用的是字符,有很多字符集,寫入和讀取的字符集要一致,不一致會亂碼。
//寫入數據
public static void main(String[] args) throws IOException {
//使用指定字符集,把字節流轉換爲字符流
OutputStreamWriter osw = new OutputStreamWriter(new
FileOutputStream("e:\\b.txt"),"UTF-8");
osw.write("漢字");
//刷新一下,但流未關閉,還能寫入數據
osw.flush();
//先刷新,在關閉此流
osw.close();
}
//從文件讀出數據
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new
FileInputStream("e:\\b.txt"),"UTF-8");
int len = 0;
char[] by = new char[1024];
while((len = isr.read(by)) != -1){
System.out.print(new String(by,0,len));
}
isr.close();
}
flush和close的區別:在寫入字符時,字符是在緩衝區的,文件裏並沒有,此時flush一下後,就會進入文件。flush能寫入數據,但並沒有把流關閉,隨後還能寫入數據。而close是刷新寫入數據後把流關閉,隨後就不能寫入數據了。
3.2 OutputStreamWriter,InputStreamReader的封裝類:FileWriter,FileReader
利用封裝的類複製文件,代碼:
public static void main(String[] args) throws IOException{
FileWriter osw = new FileWriter("e:\\b.txt");
FileReader isr = new FileReader("e:\\a.txt");
int len = 0;
char[] chars = new char[1024];
while ((len = isr.read(chars)) != -1){
osw.write(chars,0,len);
//osw.flush();
}
osw.close();
isr.close();
}
3.3 緩衝區類(高效類):BufferedWriter,BufferedReader
//寫入
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\b.txt"));
bw.write("hello");
bw.close();
}
//讀出
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("e:\\b.txt"));
int len = 0;
char[] c = new char[1024];
while((len = br.read(c)) != -1){
System.out.println(c);
}
br.close();
}
這兩個類有特殊的方法:
public void newLine():系統決定換行符
public String readLine():一次讀取一行數據,沒有數據時返回null
方法的使用:
//複製文件練習
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("e:\\a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\b.txt"));
String str = null;
while((str = br.readLine()) != null){
bw.write(str);
bw.newLine();
}
bw.close();
br.close();
}
BufferReader的子類:LineNumberReader
其特有功能:
特殊方法: int getLineNumber() :獲取當前行號
void setLineNumber(int lineNumber):設置當前行號
代碼:
public static void main(String[] args) throws IOException {
LineNumberReader lnr = new LineNumberReader(new FileReader("e:\\b.txt"));
lnr.setLineNumber(11);//從第12行開始
String str = null;
while((str = lnr.readLine()) != null){
int line = lnr.getLineNumber();
System.out.println(line +":"+str);
}
}
運行結果:
12:hello
13:world
14:java
4.數據輸入輸出流
DataOutputStream:FilterOutputStream的子類
數據輸入輸出流可以讀寫任意類型數據:
public static void main(String[] args) throws IOException {
write();
read();
}
private static void read() throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("e:\\b.txt"));
int i = dis.readInt();
char c = dis.readChar();
float f = dis.readFloat();
double d = dis.readDouble();
dis.close();
System.out.println(i);
System.out.println(c);
System.out.println(f);
System.out.println(d);
}
private static void write() throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("e:\\b.txt"));
dos.writeInt(12);
dos.writeChar('a');
dos.writeFloat(12.32f);
dos.writeDouble(14.36);
dos.close();
}
5.內存操作流
不需要文件,用於處理臨時存儲信息,程序結束,數據就從內存中消失,這個有讀有寫,對應的讀的操作類:
字節數組:java.io.InputStream 繼承者 java.io.ByteArrayInputStream
字符數組:java.io.Reader 繼承者 java.io.CharArrayReader
字符串:java.io.Reader 繼承者 java.io.StringReader
字節數組(三種類似)的寫入讀出操作:
public static void main(String[] args) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("hello".getBytes());
baos.write("java".getBytes());
//這個close()不起任何作用,內部源碼是個空的,主要是爲迎合父類操作
//baos.close();
byte[] by = baos.toByteArray();
ByteArrayInputStream bios = new ByteArrayInputStream(by);
int len = 0;
while((len = bios.read()) != -1){
System.out.print((char) len);
}
//這個close()也是
bios.close();
}
6.打印流
打印流讀字面意思就可以知道這個只有向文件寫數據,沒有讀數據:
字節打印流:java.io.FilterOutputStream 繼承者 java.io.PrintStream
字符打印流:java.io.Writer 繼承者 java.io.PrintWriter
特點:
1.只有寫數據,沒有讀數據,只能操作目的地,不能操作數據源
2.可以操作任意類型數據:print(),println()
3.如果啓用了自動刷新,能夠自動刷新
PrintWriter pw = new PrintWriter(new FileWriter("e:\\b.txt"),true);
啓用自動刷新,但必須使用println()(包含了寫入,換行,刷新)
4.該流可以直接操作文件
那些可直接操作文件的流:FileOutputStream,FileInputStream,FileWriter,FileReader,PrintStream,PrintWriter
代碼示例:
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileWriter("e:\\b.txt"),true);
// pw.print("hello");
// pw.print(100);
// pw.print("java");
pw.println("hello");
pw.println(100);
pw.println("java");
// pw.close();// 代碼中close()也會刷新,測試自動刷新,可以把close()註釋
}
7.標準輸入輸出流
public static final InputStream in
public static final PrintStream out標準輸出流:System.out 顯示器
標準輸入流:System.in 鍵盤
與我們常用的輸入輸出一樣,在輸出流中用打印流的方法都能使用 :public static final PrintStream out
public static void main(String[] args) {
PrintStream p = System.out;
p.println(11);//與下面意思一樣
System.out.println(12);
}
8.隨機訪問流
此類不是一個流,是Object的子類
融合了InputStream和OutputStream
支持對文件隨機訪問讀取和寫入
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("E:\\b.txt","rw");//第二個參數是操作文件的模式,讀寫兩種寫法一樣
// raf.writeInt(100);
// raf.writeChar('a');
// int i = raf.readInt();
// System.out.println(i);
// System.out.println("當前文件指針位置"+raf.getFilePointer());
raf.seek(4);//設置指針位置
char c = raf.readChar();
System.out.println(c);
System.out.println("當前文件指針位置"+raf.getFilePointer());
raf.close();
}
9.合併流
字面意思,一次同時讀取多個文件。只有讀操作
構造方法:SequenceInputStream(InputStream,InputStream):合併兩個文件
SequenceInputStream(Enumeration<? extends InputStream> e):合併多個文件
把a.txt和b.txt的文件內容傳到c.txt,兩種方式:
public static void main(String[] args) throws IOException {
//合併兩個文件
// InputStream is1 = new FileInputStream("e:\\a.txt");
// InputStream is2 = new FileInputStream("e:\\b.txt");
// SequenceInputStream sis = new SequenceInputStream(is1,is2);
//合併多個文件
Vector<InputStream> vi = new Vector<InputStream>();
InputStream is1 = new FileInputStream("e:\\a.txt");
InputStream is2 = new FileInputStream("e:\\b.txt");
vi.add(is1);
vi.add(is2);
//利用構造方法:SequenceInputStream(Enumeration<? extends InputStream> e)
Enumeration<InputStream> ei = vi.elements();//返回此向量的組件的枚舉。
SequenceInputStream sis = new SequenceInputStream(ei);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\c.txt"));
int len = 0;
byte[] by = new byte[1024];
while ((len = sis.read(by)) != -1){
bos.write(by,0,len);
}
bos.close();
sis.close();
}
10.序列化流反序列化流
序列化流(對像操作流):寫 ObjectOutputStream,對象--》流
把對象按照流一樣的方式存入文本文件或者在網絡中傳輸
反序列化流:讀 ObjectInputStream,流--》對象
把文本文件中的流對象或者網絡中的流對象數據還原爲對象
public static void main(String[] args) throws IOException, ClassNotFoundException {
write();
read();
}
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:\\c.txt"));
Object o = ois.readObject();
System.out.println(o);
ois.close();
}
private static void write() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e:\\c.txt"));
Student s = new Student("張三",100,120,148);
oos.writeObject(s);
oos.close();
}
/**
* Serializable:序列化
* 如果某個變量不想被序列化,可加入關鍵字transient
*/
public class Student implements Serializable {
//姓名
public String name;
//語文成績
public int chinese;
//數學成績
public int math;
//英語成績
public int english;
......
}
11.Properties
屬性集合類,是一個可以和IO流相結合使用的集合類。可以保存在流中或者從流中加載。屬性列表中每一個鍵所對應的值都是字符串。
java.util.Hashtable<Object,Object>
繼承者 java.util.Properties
特有功能
bject setProperty(String key, String value):調用 Hashtable 的方法 put。
String getProperty(String key) :用指定的鍵在此屬性列表中搜索屬性。
Set<String> stringPropertyNames() : 返回此屬性列表中的鍵集,其中該鍵及其對應值是字符串,如果在主屬性列表中未找到同名的鍵,則還包括默認屬性列表中不同的鍵。
文件與此類的結合:
方法: void load(Reader reader) 按簡單的面向行的格式從輸入字符流中讀取屬性列表(鍵和元素對)。
void store(Writer writer, String comments) 以適合使用 load(Reader) 方法的格式,將此 Properties 表中的屬性列表(鍵和元素對)寫入輸出字符。
使用代碼:
public static void main(String[] args) throws IOException {
myLoad();
myStore();
}
private static void myStore() throws IOException{
Properties p = new Properties();
Writer w = new FileWriter("e:\\c.txt");
p.setProperty("張飛","丈八蛇矛");
p.setProperty("呂布","方天畫戟");
p.setProperty("劉備","雙股劍");
p.store(w,"hero");
w.close();
}
private static void myLoad() throws IOException{
Properties p = new Properties();
Reader r = new FileReader("e:\\c.txt");
p.load(r);
System.out.println(p);
r.close();
}