流
- 在Java程序中,对于数据的输入/输出操作以“流”(stream)方式进行;J2SDK提供了各式各样的“流”类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据
1.Java流类的分类
- java.io包中定义了多个流类型(类或抽象类)来实现输入/输出功能;可以从不同的角度对其进行分类:
- 按数据流的方向不同可以分为输入流和输出流 【站在程序的角度】
- 按处理数据单位不同可以分为字节流和字符流
- 按照功能不同可以分为节点流和处理流
2.输入/输出流类
- 位于java.io内的所有流类型都分别继承自以下四种抽象流类型
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
1)InputStream
- 继承自InputStream的流都是用于向程序中输入数据,且数据的单位为字节(8bit)。【深色为节点流,浅色为处理流】
*InputStream的基本方法
- int read() throws IOException:读取一个字节并以整数的形式返回(0~255),如果返回-1即已到输入流的末尾
- int read(byte[] buffer) throws IOException:从输入流读取一些字节数,并将它们存储到缓冲区 buffer,返回实际读取的字节数,如果读取前已到输入流的末尾返回-1
- int read(byte[] buffer,int offset,int length) throws IOException:从输入流读取最多length字节的数据到一个字节数组buffer中。返回实际读取的字节数,如果读取前已到输入流的末尾返回-1
- void close() throws IOException:关闭流释放内存资源
- long skip(long n) throws IOException:跳过n个字节不读,返回实际跳过的字节数
2)OutputStream
- 继承自OutputStream的流是用于程序中输出数据,且数据的单位为字节(8bit)。【深色为节点流,浅色为处理流】
*OutputStream的基本方法
- void write(int b) throws IOException:向输出流中写入一个字节数据,该字节数据为参数b的第8位
- void write(byte[] b) throws IOException:将一个字节类型的数组中的数据写入输出流
- void write (byte[] buffer,int offset,int length) throws IOException:将一个字节类型的数组buffer中从指定位置offset开始的length个字节写入到输出流
- void close() throws IOException:关闭流释放内存资源
- void flush() throws IOException:将输出流中缓冲的数据全部写出到目的地【先写flush再写close】
3)Reader
- 继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符(16bit)。【深色为节点流,浅色为处理流】
*Reader的基本方法
- int read() throws IOException:读取一个字符并以整数的形式返回(0~255),如果返回-1即已到输入流的末尾
- int read(char[] cbuf) throws IOException:读取一系列字符并存储到一个输出cbuf中,返回实际读取的字符数,如果读取前已到输入流的末尾返回-1
- int read(char[] cbuf,int offset,int length) throws IOException:从输入流读取最多length字符的数据到一个字节数组cbuf中。返回实际读取的字符数,如果读取前已到输入流的末尾返回-1
- void close() throws IOException:关闭流释放内存资源
- long skip(long n) throws IOException:跳过n个字符不读,返回实际跳过的字符数
4)Writer
- 继承自Writer的流都是用于向程序中输出数据,且数据的单位为字符(16bit)。【深色为节点流,浅色为处理流】
*Writer的基本方法
- void write(int c) throws IOException:向输出流中写入一个字符数据,该字符数据为参数c的第16位
- void write(char[] cbuf) throws IOException:将一个字符类型的数组中的数据写入输出流
- void write (char[] cbuf,int offset,int length) throws IOException:将一个字符类型的数组cbuf中从指定位置offset开始的length个字符写入到输出流
- void write(String str) throws IOException:讲一个字符串中的字符写入到输出流
- void write(String str,int offset,int length) throws IOException:将一个字符串从offset开始的length个字符写入到输出流
- void close() throws IOException:关闭流释放内存资源
- void flush() throws IOException:将输出流中缓冲的数据全部写出到目的地【先写flush再写close】
3.节点流和处理流
1)节点流
- 节点流为可以从一个特定的数据源(节点)读写数据(如:文件,内存)
类型 | 字符流 | 字节流 |
---|---|---|
File(文件) | FileReader;FileWriter | FileInputStream;FileOutputStream |
Memory Array | CharArrayReader;CharArrayWriter | ByteArrayInputStream;ByteArrayOutputStream |
Memory String | StringReader;StringWriter | — |
Pipe | PipedReader;PipedWriter | PipedInputStream;PipedOutPutStream |
2)处理流
- 处理流是“连接”在已存在的流(节点流或处理流)之上,通过数据的处理为程序提供更为强大的读写功能。【套在其他流之上的】
处理类型 | 字符流 | 字节流 |
---|---|---|
Buffering | BufferedReader;BufferedWriter | BufferedInputStream;BufferedOutputStream |
Filtering | FilterReader;FilterWriter | FilterInputStream;FilterOutputStream |
Converting between bytes and character | InputStreamReader;OutputStreamWriter | |
Object Serialization | — | ObjectInputStream;ObjectOutputStream |
Data conversion | — | DataInputStream;DataOutputStream |
Counting | LineNumberReader | LineNumberInputStream |
Peeking ahead | PusbackReader | PushbackInputStream |
Printing | PrintWriter | PrintStream |
4.文件流
1)FileInputStream和FileOutputStream
-
FileInputStream和FileOutputStream分别继承自InputStream和OutputStream用于向文件中输入和输出字节
-
FileInputStream和FileOutputStream类支持其父类InputStream和OutputStream所提供的的数据读写方法
-
注意:
①在实例化InputStream和OutputStream流时要用try-catch语句以处理其可能抛出的FileNotFoundException。
②在读写数据时也要用try-catch语句以处理可能抛出的IOException
③FileNotFoundException是IOException的子类
(1)FileInputStream举例
package com.stream;
/*
@author qw
@date 2020/8/6 - 22:08
**/
import java.io.*;
public class Demo01 {
public static void main(String[] args) {
int b = 0;
FileInputStream in = null;
try {
in = new FileInputStream("D:\\javaEx\\io\\TestFileInputStream.java");
} catch (FileNotFoundException e) {
System.out.println("找不到指定文件");
System.exit(-1);//系统退出
}
try {
long num = 0;
while ((b = in.read()) != -1) {
System.out.println((char) b);
num++;
}
in.close();
System.out.println();
System.out.println("共读取了" + num + "个字节");
} catch (IOException e1) {
System.out.println("文件读取错误");
System.exit(-1);
}
}
}
(2)FileOutputStream举例
package com.stream;
/*
@author qw
@date 2020/8/6 - 22:16
**/
import java.io.*;
public class Demo02 {
public static void main(String[] args) {
int b = 0;
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("D:\\javaEx\\HelloWorld.java");
out = new FileOutputStream("D:\\javaEx\\io\\HW.java");
while ((b = in.read()) != -1) {
out.write(b);
}
in.close();
out.close();
} catch (FileNotFoundException e2) {
System.out.println("找不到指定文件");
System.exit(-1);
} catch (IOException e1) {
System.out.println("文件复制错误");
System.exit(-1);
}
System.out.println("文件已复制");
}
}
2)Reader和Writer
(1)Reader举例
package com.stream;
/*
@author qw
@date 2020/8/6 - 22:23
**/
import java.io.*;
public class Demo03 {
public static void main(String[] args) {
FileReader fr = null;
int c = 0;
try {
fr=new FileReader("D:\\javaEx\\io\\TestFileReader.java");
int ln = 0;
while ((c = fr.read()) != -1) {
System.out.println((char)c);
}
fr.close();
}catch (FileNotFoundException e) {
System.out.println("找不到指定文件");
} catch (IOException e) {
System.out.println("文件复制错误");
}
}
}
(2)Writer举例
package com.stream;
/*
@author qw
@date 2020/8/6 - 22:23
**/
import java.io.*;
public class Demo04 {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("D:\\javaEx\\unicode.dat");
for (int i = 0; i < 1000; i++) {
fw.write(i);
}
fw.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件写入错误");
System.exit(-1);
}
}
}
5.缓冲流
-
缓冲流要“套接“在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了 一些新的方法
-
提供了四种缓冲流:BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream
-
注意:
①缓冲输入流支持其父类的mark和reset方法
②BufferedReader提供了readLine方法用于读取一行字符串(以\r或\n分隔)
③BufferedWriter提供了newLine用于写入一个行分隔符
④对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush方法使内存中的数据立刻写出
1)BufferedInputStream举例
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("D:\\javaEx\\HelloWorld.java");
BufferedInputStream bis = new BufferedInputStream(fis);
int c = 0;
System.out.println(bis.read());
bis.mark(100);//标记从第100个字节开始读
for (int i = 0; i < 10 && (c = bis.read()) != -1; i++) {
System.out.print((char) c + " ");
}
bis.reset();//重置恢复到 第100
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2)BufferedReader和BufferedWriter举例
public static void main(String[] args) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\javaEx\\dat2.txt"));
BufferedReader br = new BufferedReader(new FileReader("D:\\javaEx\\HelloWorld.java"));
String s = null;
for (int i = 0; i < 100; i++) {
s = String.valueOf(Math.random());
bw.write(s);
bw.newLine();//换新行
}
bw.flush();
while ((s = br.readLine())!= null) {
System.out.println(s);
}
bw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
6.数据流
- DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,它属于处理流,需要分别“套接”在InputStream和OutputStream类型的节点流上
- DataInputStream和DataOutputStream提供了可以存取与机器无关的Java原始类型数据(如:int,double等)的方法
- DataInputStream和DataOutputStream的构造方法为:
- DataInputStream(InputStream in)
- DataOutputStream(OutputStream out)
package com.stream;
/*
@author qw
@date 2020/8/7 - 15:58
**/
import java.io.*;
public class Demo09 {
public static void main(String[] args) {
//字节数组输出流在内存中创建一个字节数组缓冲区,
//所有发送到输出流的数据保存在该字节数组缓冲区中
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
try {
dos.writeDouble(Math.random());
dos.writeBoolean(true);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
System.out.println(bais.available()); //9
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.readDouble());//先写入的先读出
System.out.println(dis.readBoolean());
dos.close();
dis.close();
} catch (IOException e) {
e.printStackTrce();
}
}
}
7.转换流
- InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换
- InputStreamReader需要和InputStream“套接”
- OutputStreamWriter需要和OutputStream“套接”
- 转换流在构造时可以指定其编码集合,例如:InputStream isr = new InputStreamReader(System.in,“ISO8859_1”)
package com.stream;
/*
@author qw
@date 2020/8/7 - 10:24
**/
import java.io.*;
public class Demo07 {
public static void main(String[] args) {
try {//使用处理流后,能够直接写入字符串,而不用拆分成字节再写入
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\javaEx\\char.txt"));
osw.write("microsoftdjfhvysm");
System.out.println(osw.getEncoding());//GBK
osw.close();
osw = new OutputStreamWriter(new FileOutputStream("D:\\javaEx\\char.txt", true), "ISO8859_1");
//true表示,在原文档的基础上继续添加
osw.write("microsoftdjfhvysm");
System.out.println(osw.getEncoding());//ISO8859_1
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.stream;
/*
@author qw
@date 2020/8/7 - 11:11
**/
import java.io.*;
public class Demo08 {
public static void main(String[] args) {
InputStreamReader isr = new InputStreamReader(System.in);//键盘输入
BufferedReader br = new BufferedReader(isr);
String s = null;
try {
s = br.readLine();
while (s != null) {
if (s.equalsIgnoreCase("exit")) {
break;
}
System.out.println(s.toUpperCase());
s = br.readLine();
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
8.Print流
- PrintWriter和PrintStream都属于输出流,分别针对字符和字节
- PrintWriter和PrintStream提供了重载的print
- Println方法用于多种数据类型的输出
- PrintWriter和PrintStream的输出操作不会抛出异常,用于通过检测错误状态获取错误信息
- PrintWriter和PrintStream有自动flush功能
package com.stream;
/*
@author qw
@date 2020/8/7 - 21:18
**/
import java.io.*;
public class Demo10 {
public static void main(String[] args) {
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream("D:\\javaEx\\log.dat");
ps = new PrintStream(fos);
//PrintStream处理流套接在FileOutputStream上
} catch (IOException e) {
e.printStackTrace();
}
if (ps != null) {
System.setOut(ps);//设置新的out,指向了ps
}
int ln = 0;
for (char c = 0; c <= 60000; c++) {
System.out.print(c + " ");
//使用新的out,将数据print在log.dat文件中
if (ln++ >= 100) {
System.out.println();
ln = 0;
}
}
}
}
package com.stream;
/*
@author qw
@date 2020/8/7 - 21:40
**/
import java.util.*;
import java.io.*;
public class Demo11 {
public static void main(String[] args) {
String s = null;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
FileWriter fw = new FileWriter("D:\\javaEx\\logfile.log", true);
//true表示:继续写入数据时,追加在原文件的后面;往往用于做日志的记录
PrintWriter log = new PrintWriter(fw);
//在FileWriter上套接PrintWriter
while ((s = br.readLine()) != null) {
if (s.equalsIgnoreCase("exit")) {
break;
}
System.out.println(s.toUpperCase());
log.println("------");
log.println(s.toUpperCase());
log.flush();
}
log.println("===" + new Date() + "===");
log.flush();
log.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
9.Object流
- 直接将Object写入或读出
1)transient关键字
- 用来修饰成员变量
2)serializable接口
- serializable 接口:序列化,可以被序列化的,若确实需要将某个类的对象写在硬盘上或网络上,想把他们序列化成一个字节流,就必须实现这个这个接口(标记性接口, 用来标记一下,这个类的对象可以被序列化,那么这个类到底是怎么被序列化的,自己不能控制,是 JDK 直接帮你控制这个类的对象的序列化过程).
3)externalizable接口
- 通过 readExternal()、 writeExternal() 这个两个方法,自己实现序列化过程.
package com.stream;
/*
@author qw
@date 2020/8/7 - 22:28
**/
import java.io.*;
public class Demo12 {
public static void main(String[] args) {
T t = new T();
t.j = 16;
try {
FileOutputStream fos = new FileOutputStream("D:\\javaEx\\io\\testobjectio.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(t);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("D:\\javaEx\\io\\testobjectio.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
T tReaded = (T) ois.readObject();
System.out.println(tReaded.i + " " + tReaded.j + " " + tReaded.d + " " + tReaded.k);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class T implements Serializable{
int i=10;
int j=9;
double d=2.3;
transient int k=15;
//该参数不需要序列化,即它的值不写入到计算机中,最后读取是零
}