1.流的概念
Java采用流的机制来实现输入/输出。
流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样,如下图:
输出流:
输入流:
2.Java输入输出流
InputStream:输入字节流。继承自InputStream的流都是用于向程序中输入数据的,且数据单位都是字节(8位 byte[])。
-
InputStream 是所有的输入字节流的父类,它是一个抽象类。
-
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据。
-
ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
Inputstream类中的常用方法:
(1) public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
(2) public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
(3) public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。
(4) public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用,
(5) public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取
(6) public int close( ) :我们在使用完后,必须对我们打开的流进行关闭.
OutputSteam:输出字节流。继承自OutputStream的流都是程序用于向外输出数据的,且数据单位都是字节(8位 byte[])。
-
OutputStream 是所有的输出字节流的父类,它是一个抽象类。
-
ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
-
ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
OutputSteam类中的常用方法:
(1) public void write(byte b[ ]):将参数b中的字节写到输出流。
(2) public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。
(3) public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。
(4) public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
(5) public void close( ) : 关闭输出流并释放与流相关的系统资源。
Reader:输入字符流。继承自Reader的流都是用于向程序中输入数据的,且数据单位都是字符(16位 char[])。
-
Reader 是所有的输入字符流的父类,它是一个抽象类。
-
CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
-
BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
-
FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
-
InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。
Reader类中的常用方法:
(1) public int read() throws IOException; //读取一个字符,返回值为读取的字符
(2) public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/
(3) public abstract int read(char cbuf[],int off,int len) throws IOException; /*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/
Writer:输出字符流。继承自Writer的流都是程序用于向外输出数据的,且数据单位都是字符(16位 char[])。
-
Writer 是所有的输出字符流的父类,它是一个抽象类。
-
CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
-
BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
-
PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
-
OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类。
Writer类中的常用方法:
(1) public void write(int c) throws IOException; //将整型值c的低16位写入输出流
(2) public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流
(3) public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流
(4) public void write(String str) throws IOException; //将字符串str中的字符写入输出流
(5) public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流
(6) flush( ) //刷空输出流,并输出所有被缓存的字节。
(7) close() 关闭流 public abstract void close() throws IOException
Java输入输出流有两个对称性
-
输入-输出对称: InputStream和OutputStream各自在Byte流输入和输出的两个平行结构的等级的根部;Reader和Writer各自在Char流输入和输出的两个平行结构的根部
-
byte-char对称:InputStream和Reader的子类分别负责Byte和Char流的输入;OutputStream和Writer的子类分别负责Byte和Char流的输出。分别形成平行的等级结构。
3.常用的IO流
1.字节流中原始流的代表:FileInputStream FileOutputStream
FileInputStream 从一个文件中读取byte[]
FileOutputStream 将byte[]写入到一个文件中
FileInputStream/FileOutputStream的例子
具体的内容是:从利用FileInputStream从input.txt中读出byte流,用某种编码格式转换为String显示出来,然后将String转换成byte流,利用FileOutputStream将byte流写入到output.txt中
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.nio.ByteBuffer; 7 import java.nio.charset.Charset; 8 9 public class FileStreamDemo { 10 public static void main(String[] args) { 11 try { 12 FileInputStream fis = new FileInputStream(new File("input.txt")); 13 byte[] bis = new byte[fis.available()]; 14 fis.read(bis); 15 fis.close(); 16 /* 17 * 关于byte[]转换为String编码配置有两种方法,建议使用第二种方案 1.String str = new 18 * String(b,"charsetname") 2.Charset charset = = 19 * Charset.forName("charsetname"); String str = 20 * charset.decode(ByteBuffer.wrap(b)).toString(); 21 */ 22 Charset charset = Charset.forName("UTF-8"); 23 String str = charset.decode(ByteBuffer.wrap(bis)).toString(); 24 // String str = new String(bis); 25 // //byte转换为String,默认的编码是"ISO-8859-1",即根据编辑器的编码来确定编码方式 26 System.out.println(str); 27 28 FileOutputStream fos = new FileOutputStream(new File("output.txt")); 29 byte[] bos = str.getBytes(); 30 fos.write(bos); 31 fos.close(); 32 33 } catch (FileNotFoundException e) { 34 // TODO Auto-generated catch block 35 e.printStackTrace(); 36 } catch (IOException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 41 } 42 }
2.字节流中装饰流之BufferInputStream BufferOutputStream
BufferInputStream:将原始InputStream中的byte[]读到内存缓存区中,然后从缓冲区读取byte[]
BufferOutputStream:向一个缓冲区中写入byte[],将缓冲区中的byte[]写入到原始outputStream中
BufferInputStream和BufferoutputStream对原始输入输出流进行装饰,使得流的读/写操作使用缓冲机制,这样不会对每次的流读/写操作都产生一个物理的读/写操作,从而提高了程序的效率。涉及物理流的地方,如控制台I/O,文件I/O等,都应当使用这个装饰流处理器。
举例:
1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.nio.ByteBuffer; 9 import java.nio.charset.Charset; 10 11 public class BufferStreamDemo { 12 public static void main(String[] args) { 13 try { 14 15 FileInputStream fis = new FileInputStream(new File("input.txt")); 16 BufferedInputStream bfis = new BufferedInputStream(fis); 17 byte[] bis = new byte[bfis.available()]; 18 bfis.read(bis); 19 bfis.close(); 20 fis.close(); 21 /* 22 * 关于byte[]转换为String编码配置有两种方法,建议使用第二种方案 1.String str = new 23 * String(b,"charsetname") 2.Charset charset = = 24 * Charset.forName("charsetname"); String str = 25 * charset.decode(ByteBuffer.wrap(b)).toString(); 26 */ 27 Charset charset = Charset.forName("UTF-8"); 28 String str = charset.decode(ByteBuffer.wrap(bis)).toString(); 29 // String str = new String(bis); 30 // //byte转换为String,默认的编码是"ISO-8859-1",即根据编辑器的编码来确定编码方式 31 System.out.println(str); 32 33 FileOutputStream fos = new FileOutputStream(new File("output.txt")); 34 BufferedOutputStream bfos = new BufferedOutputStream(fos); 35 byte[] bos = str.getBytes(); 36 bfos.write(bos); 37 bfos.close(); 38 fos.close(); 39 } catch (FileNotFoundException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 } catch (IOException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 } 46 47 } 48 }
3.字节装饰流之ObjectInputStream ObjectOutputStream
ObjectInputStream :对象输入流,将使用ObjectOutputStream串行化的原始数据类型和对象重新并行化
ObjectOutputStream:对象输出流,将原始数据类型和对象串行化
使用ObjectInputStream/ObjectOutputStream类所读写的对象必须实现Serializable接口,对象中的transient和static类型成员变量不会被读取和写入
举例:
1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.nio.ByteBuffer; 9 import java.nio.charset.Charset; 10 11 public class BufferStreamDemo { 12 public static void main(String[] args) { 13 try { 14 15 FileInputStream fis = new FileInputStream(new File("input.txt")); 16 BufferedInputStream bfis = new BufferedInputStream(fis); 17 byte[] bis = new byte[bfis.available()]; 18 bfis.read(bis); 19 bfis.close(); 20 fis.close(); 21 /* 22 * 关于byte[]转换为String编码配置有两种方法,建议使用第二种方案 1.String str = new 23 * String(b,"charsetname") 2.Charset charset = = 24 * Charset.forName("charsetname"); String str = 25 * charset.decode(ByteBuffer.wrap(b)).toString(); 26 */ 27 Charset charset = Charset.forName("UTF-8"); 28 String str = charset.decode(ByteBuffer.wrap(bis)).toString(); 29 // String str = new String(bis); 30 // //byte转换为String,默认的编码是"ISO-8859-1",即根据编辑器的编码来确定编码方式 31 System.out.println(str); 32 33 FileOutputStream fos = new FileOutputStream(new File("output.txt")); 34 BufferedOutputStream bfos = new BufferedOutputStream(fos); 35 byte[] bos = str.getBytes(); 36 bfos.write(bos); 37 bfos.close(); 38 fos.close(); 39 } catch (FileNotFoundException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 } catch (IOException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 } 46 47 } 48 }
1 import java.io.*; 2 3 public class Student implements Serializable { 4 5 String name; 6 int id; 7 int age; 8 String department; 9 10 public Student(String name, int id, int age, String department) { 11 this.age = age; 12 this.department = department; 13 this.id = id; 14 this.name = name; 15 } 16 }
4.字节装饰流之DataInputStream DataOutputStream
DataInputStream:提供基于多字节的读取方法,可以读取原始数据类型的数据
DataOutputStream:提供基于多字节的写出方法,可以写出原始数据类型的数据
举例:
1 public class Member { 2 private String name; 3 private int age; 4 5 public Member() { 6 } 7 8 public Member(String name, int age) { 9 this.name = name; 10 this.age = age; 11 } 12 13 public void setName(String name) { 14 this.name = name; 15 } 16 17 public void setAge(int age) { 18 this.age = age; 19 } 20 21 public String getName() { 22 return name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 }
1 import java.io.*; 2 3 public class DataStreamDemo { 4 public static void main(String[] args) { 5 Member[] members = { new Member("Justin", 90), new Member("momor", 95), 6 new Member("Bush", 88) }; 7 try { 8 DataOutputStream dataOutputStream = new DataOutputStream( 9 new FileOutputStream(new File("file.txt"))); 10 11 for (Member member : members) { 12 // 写入UTF字符串 13 dataOutputStream.writeUTF(member.getName()); 14 // 写入int数据 15 dataOutputStream.writeInt(member.getAge()); 16 } 17 18 // 所有数据至目的地 19 dataOutputStream.flush(); 20 // 关闭流 21 dataOutputStream.close(); 22 23 DataInputStream dataInputStream = new DataInputStream( 24 new FileInputStream(new File("file.txt"))); 25 26 // 读出数据并还原为对象 27 for (int i = 0; i < members.length; i++) { 28 // 读出UTF字符串 29 String name = dataInputStream.readUTF(); 30 // 读出int数据 31 int score = dataInputStream.readInt(); 32 members[i] = new Member(name, score); 33 } 34 35 // 关闭流 36 dataInputStream.close(); 37 38 // 显示还原后的数据 39 for (Member member : members) { 40 System.out 41 .printf("%s %d%n", member.getName(), member.getAge()); 42 } 43 } catch (IOException e) { 44 e.printStackTrace(); 45 } 46 } 47 }
5.字符流 之StringReader和StringWriter
StringReader:数据从String中读取到char[]
StringWriter:将char[]写入到String中
举例:
1 import java.io.IOException; 2 import java.io.StringReader; 3 import java.io.StringWriter; 4 5 public class StringStreamTest { 6 public static void main(String[] args) { 7 String str = "abcdefghijklmn"; 8 transform(str); 9 } 10 11 public static void transform(String str) { 12 StringReader sr = new StringReader(str); 13 StringWriter sw = new StringWriter(); 14 char[] chars = new char[1024]; 15 try { 16 int len = 0; 17 while ((len = sr.read(chars)) != -1) { 18 String strRead = new String(chars, 0, len).toUpperCase(); 19 System.out.println(strRead); 20 sw.write(strRead); 21 sw.flush(); 22 } 23 sr.close(); 24 sw.close(); 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } finally { 28 sr.close(); 29 try { 30 sw.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 } 36 }
6.字符装饰流之 BufferedReader/BufferedWriter
BufferedReader/BufferedWriter的作用和BufferInputStream/BufferOutputStream类似,但BufferedReader提供了一个readline方法,可以将存储的一行的char[]读取出来
举例:
1 import java.io.*; 2 3 class BufferReaderDemo { 4 public static void main(String arg[]) throws IOException { 5 BufferedReader b = new BufferedReader(new FileReader("c.txt")); 6 boolean c; 7 do { 8 String s = b.readLine(); 9 System.out.println(s); 10 } while (c = b.read() != -1); 11 } 12 }
7.从byte流到char流的适配 InputStreamReader和OutputStreamWriter
byte流到char流的适配是通过InputStreamReader和OutputStreamWriter来解决的
InputStreamReader:是字节流通向字符流的桥梁。你可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如 GBK 等
要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter :是字符流通向字节流的桥梁。
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
举例:
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.io.OutputStreamWriter; 8 9 public class StreamReaderWriterDemo { 10 public static void main(String[] args) { 11 try { 12 13 BufferedReader bufr = new BufferedReader(new InputStreamReader( 14 new FileInputStream("f:\01.txt"))); 15 16 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter( 17 new FileOutputStream("f:\02.txt"))); 18 19 int ch = 0; 20 21 // 以字符方式显示文件内容 22 while ((ch = bufr.read()) != -1) { 23 System.out.print((char) ch); 24 bufw.write(ch); 25 } 26 if (bufr != null) 27 bufr.close(); 28 if (bufw != null) 29 bufw.close(); 30 } catch (ArrayIndexOutOfBoundsException e) { 31 e.printStackTrace(); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 } 36 }
8. InputStreamReader和OutputStreamWriter的子类:FileReader 和FileWriter
FileReader:文件字节流通向字符流的桥梁
FileWriter:是字符流通向文件字节流的桥梁。
举例:
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileReader; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 7 public class TestWriter { 8 // 功能:读取E:/Test.txt文件的内容(一行一行读),并将其内容写入E:/Jack.txt中 9 // 知识点:java读文件、写文件---<以字符流方式> 10 public static void main(String[] args) { 11 try { 12 // 创建FileReader对象,用来读取字符流 13 FileReader fr = new FileReader("E:/Test.txt"); 14 // 缓冲指定文件的输入 15 BufferedReader br = new BufferedReader(fr); 16 // 创建FileWriter对象,用来写入字符流 17 FileWriter fw = new FileWriter("E:/Jack.txt"); 18 // 将缓冲对文件的输出 19 BufferedWriter bw = new BufferedWriter(fw); 20 // 定义一个String类型的变量,用来每次读取一行 21 String myreadline; 22 while (br.ready()) { 23 // 读取一行 24 myreadline = br.readLine(); 25 // 写入文件 26 bw.write(myreadline); 27 bw.newLine(); 28 // 在屏幕上输出 29 System.out.println(myreadline); 30 } 31 // 刷新该流的缓冲 32 bw.flush(); 33 bw.close(); 34 br.close(); 35 fw.close(); 36 br.close(); 37 fr.close(); 38 39 } catch (IOException e) { 40 e.printStackTrace(); 41 } 42 } 43 }
9.PrintStream OutputStream
PrintStream在OutputStream基础之上提供了增强的功能,即可以方便地输出各种类型的数据(而不仅限于byte型)的格式化表示形式。PrintStream的方法从不抛出IOException。
System.out是PrintStream的实例(注意System.in是一个BufferInputStream)
下面是一个Socket实例,使用了PrintStream System.out System.in
1 package zyb.org.client; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintStream; 7 import java.net.Socket; 8 import java.net.SocketTimeoutException; 9 10 public class Client1 { 11 public static void main(String[] args) throws IOException { 12 //客户端请求与本机在20006端口建立TCP连接 13 Socket client = new Socket("127.0.0.1", 20006); 14 client.setSoTimeout(10000); 15 //获取键盘输入 16 BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 17 //获取Socket的输出流,用来发送数据到服务端 18 PrintStream out = new PrintStream(client.getOutputStream()); 19 //获取Socket的输入流,用来接收从服务端发送过来的数据 20 BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())); 21 boolean flag = true; 22 while(flag){ 23 System.out.print("输入信息:"); 24 String str = input.readLine(); 25 //发送数据到服务端 26 out.println(str); 27 if("bye".equals(str)){ 28 flag = false; 29 }else{ 30 try{ 31 //从服务器端接收数据有个时间限制(系统自设,也可以自己设置),超过了这个时间,便会抛出该异常 32 String echo = buf.readLine(); 33 System.out.println(echo); 34 }catch(SocketTimeoutException e){ 35 System.out.println("Time out, No response"); 36 } 37 } 38 } 39 input.close(); 40 if(client != null){ 41 //如果构造函数建立起了连接,则关闭套接字,如果没有建立起连接,自然不用关闭 42 client.close(); //只关闭socket,其关联的输入输出流也会被关闭 43 } 44 } 45 }
参考文章:
Java输入输出流详解 http://blog.csdn.net/zsw12013/article/details/6534619
Java IO流分析整理 http://www.th7.cn/Program/java/201406/214540.shtml
Java输入输出流 http://blog.csdn.net/hguisu/article/details/7418161
《Java与模式》第27章 专题:设计模式在Java I/O库中的应用
ObjectInputStream与ObjectOutputStream类 http://blog.sina.com.cn/s/blog_77cb34170100r5o6.html
使用StringReader和StringWriter操作字符串 http://blog.csdn.net/zhuhezan/article/details/6526915
InputStreamReader和OutputStreamWriter的用法 http://blog.csdn.net/z69183787/article/details/8179889
Java FileReader FileWriter 示例 http://blog.163.com/jackswu@yeah/blog/static/1406291232011076011170/
printStream 和printWriter区别 http://blog.csdn.net/y3wegy/article/details/8783314
【Java TCP/IP Socket】TCP Socket(含代码) http://blog.csdn.net/ns_code/article/details/14105457