流的概念
流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以使文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。
流的分类
① 流按其流向分为“输入流”和“输出流”。
② 流按数据传输单位分为“字节流”和“字符流”。
a) “字节流”用来读写8位二进制的字节。
b) “字符流”用来读写16位二进制字符。
③ 流按功能分为“节点流”和“过滤流”。
a) “节点流”用于直接操作目标设备的流。例如:磁盘或一块内存区域。
b) “过滤流”是对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能。
字节流
字节流类用于向字节流读取8位二进制的字节。一般地,字节流主要用于读写诸如图像或声音等二进制数据。
字节流类以InputStream和OutputStream为顶层类。它们都是抽象类。
一、InputStream
① InputStream是定义了字节输入流的抽象类。
② InputStream中定义的方法
a) public abstract int read()
b) public int read(byte[] b)
c) public int read(byte[] b,int off,int len)
d) public long skip(long n)
e) public int available()
f) public void close()
二、OutputStream
① OutputStream是定义了字节输出流的抽象类。
② 该类所有方法返回void值,在出错情况下抛IOException异常
③ OutputStream中定义的方法
g) public abstract void write(int b)
h) public void write(byte[] b)
i) public void write(byte[] b,int off,int len)
j) public void flush()
k) public void close()
每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区。
三、FileInputStream
① FileInputStream类表示能从文件读取字节的InputStream类
② 构造方法
a) FileInputStream(String filePath)
b) FileInputStream(File fileObj)
四、FileOutputStream
① FileOutputStream表示能向文件写入字节的OutputStream类
② 构造方法
a) FileOutputStream(String filePath)
b) FileOutputStream(File fileObj)
c) FileOutputStream(String filePath,boolean append)
示例:拷贝指定文件到指定目录
1 class FileCopyUtil { 2 public static void copyFile(File src, File dst) throws IOException { 3 FileInputStream fis = new FileInputStream(src); 4 FileOutputStream fos = new FileOutputStream(dst); 5 long time1 = System.currentTimeMillis(); 6 int data = -1; 7 while ((data = fis.read()) != -1) { 8 fos.write(data); 9 } 10 fis.close(); 11 fos.close(); 12 long time2 = System.currentTimeMillis(); 13 System.out.println("复制完成,共花费:" + (time2 - time1) + "毫秒"); 14 } 15 }
主方法:
1 try { 2 FileCopyUtil.copyFile(new File("d:/zhangsan/tu.png"), new File("e:/fuzhi.png")); 3 } catch (IOException e) { 4 e.printStackTrace(); 5 }
输出结果
复制完成,共花费:1545毫秒
单一张71K的图片就花费了1545毫秒,由此可见效率是极低的,因为它是读一个写一个,我们可以换种思路,先全部读到一个缓冲区,再将内容一次性写入。这里就好比喝水时一滴一滴地喝还是接到杯子里再喝。
改造下方法,如下:
1 class FileCopyUtil { 2 public static void copyFile(File src, File dst) throws IOException { 3 FileInputStream fis = new FileInputStream(src); 4 FileOutputStream fos = new FileOutputStream(dst); 5 byte[] buff = new byte[1024 * 1024];// 创建一个1M大小的缓冲区,用来存放输入流中的字节 6 int len = 0;// 用来保存实际读到的字节数 7 long time1 = System.currentTimeMillis(); 8 while ((len = fis.read(buff)) != -1) { 9 fos.write(buff, 0, len); 10 } 11 fis.close(); 12 fos.close(); 13 long time2 = System.currentTimeMillis(); 14 System.out.println("复制完成,共花费:" + (time2 - time1) + "毫秒"); 15 } 16 }
同样读取那张图片,输出结果:
复制完成,共花费:3毫秒
再复制一个8M的mp3格式文件,输出结果:
复制完成,共花费:39毫秒
五、ByteArrayInputStream
①ByteArrayInputStream是把字节数组当成源的输入流。
②两个构造方法,每个都需要一个字节数组提供数据源:
a) ByteArrayInputStream(byte array[])
b) ByteArrayInputStream(byte array[],int start,int numBytes)
1 String str="hello,HangZhou"; 2 ByteArrayInputStream bis=new ByteArrayInputStream(str.getBytes()); 3 int data=-1; 4 while((data=bis.read())!=-1) 5 { 6 System.out.println((char)data); 7 }
输出结果:
h e l l o , H a n g Z h o u
六、ByteArrayOutputStream
①ByteArrayOutputStream是把字节数组当作目标的输出流。
②两个构造方法:
a) ByteArrayOutputStream()
创建一个新的byte数组输出流
b) ByteArrayOutputStream(int numBytes)
创建一个新的byte数组输出流,具有指定大小缓冲区(字节为单位)
1 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 2 bos.write(97); 3 bos.write(65); 4 try { 5 bos.write("hello,word".getBytes()); 6 } catch (IOException e) { 7 e.printStackTrace(); 8 } 9 byte[] buff = bos.toByteArray(); 10 for (byte b : buff) { 11 System.out.print((char)data+" "); 12 } 13 14 FileOutputStream fos=new FileOutputStream("d://aa.txt", true); 15 bos.writeTo(fos);//把ByteArrayOutputStream内部缓冲区的数据写到对应的文件输出流中 16 fos.close();
输出结果:
aAhello,word
并会在d盘下创建一个aa.txt文件,里面内容为输出结果的内容,再次执行将追加一次执行结果的内容。
过滤流
① 过滤流仅仅是为底层透明地提供扩展功能的输入流(输出流)的包装。这些流一般由普通类的方法(即过滤流的一个父类)访问。
② 过滤字节流FilterInputStream和FilterOutputStream。构造方法:
a) FilterInputStream(InputStream is)
b) FilterOutputStream(OutputStream os)
③ 这些类提供的方法和InputStream及OutputStream类的方法相同。
④ 常用的过滤流BufferedInputStream和BufferedOutputStream,DataInputStream和DataOutputStream
BufferedInputStream,BufferedOutputStream用法举例
使用过滤流来改写上面的复制方法
1 class FileUtil { 2 public static void copyFile(File src, File dst) throws IOException { 3 FileInputStream fis = new FileInputStream(src); 4 FileOutputStream fos = new FileOutputStream(dst); 5 BufferedInputStream bis=new BufferedInputStream(fis); 6 BufferedOutputStream bos=new BufferedOutputStream(fos); 7 8 int data = 0;// 用来保存实际读到的字节数 9 long time1 = System.currentTimeMillis(); 10 while ((data = bis.read()) != -1) { 11 bos.write(data); 12 } 13 bis.close(); 14 bos.close(); 15 long time2 = System.currentTimeMillis(); 16 System.out.println("复制完成,共花费:" + (time2 - time1) + "毫秒"); 17 } 18 }
主方法:
1 try { 2 FileUtil.copyFile(new File("d:/zhangsan/Closer To Me.mp3"), new File( 3 "e:/fuzhi.mp3")); 4 } catch (IOException e) { 5 e.printStackTrace(); 6 } 7 }
复制同样的一首歌,输出结果:
复制完成,共花费:905毫秒
时间增加了很多,但也比文件直接读写快了不少。Buffered中自带一个8k左右的缓冲区。
DataInputStream和DataOutputStream用法举例:
写入文件:
1 String name="zhangsan"; 2 int age=10; 3 boolean flag=true; 4 char sex='男'; 5 double money=123.45; 6 7 DataOutputStream dos=new DataOutputStream(new FileOutputStream("d:/b.txt")); 8 dos.writeUTF(name); 9 dos.writeInt(age); 10 dos.writeBoolean(flag); 11 dos.writeChar(sex); 12 dos.writeDouble(money); 13 dos.close();
打开b.txt后发现有乱码,那是因为写进去的是二进制
读文件:
1 DataInputStream dis=new DataInputStream(new FileInputStream("d:/b.txt")); 2 //读的顺序必须与写入的顺序一致 3 System.out.println(dis.readUTF()); 4 System.out.println(dis.readInt()); 5 System.out.println(dis.readBoolean()); 6 System.out.println(dis.readChar()); 7 System.out.println(dis.readDouble()); 8 dis.close();
输出结果:
zhangsan
10
true
男
123.45
过滤流总结:
BufferedInputStream与BufferedOutputStream
需要使用已经存在的节点流来构造,提供缓冲的读写,提高了读写的效率。
DataInputStream与DataOutputStream
数据输入输出流允许应用程序读写基本Java数据类型。应用程序可以使用数据输出流写入,稍后由数据输入流读取。读写顺序要保持一致。
来源:https://www.cnblogs.com/wzy330782/p/5471515.html