常用的其它流
1、数据流(DataInputStream/DataOutputStream)
java.io
类 DataInputStream
java.lang.Object 继承者
java.io.InputStream
继承者
java.io.FilterInputStream
继承者
java.io.DataInputStream
public class DataInputStream
extends FilterInput Stream
implements DataInput
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责。
数据输出流类似,具体可查看jdk文档。
数据的访问和其它流有所不同
先写出,后读取
*读取的顺序与写出保持一致
写出的时候就可以使用ByteArrayOutputStream 写到内存里
1 package com.sxt.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.ByteArrayInputStream; 6 import java.io.ByteArrayOutputStream; 7 import java.io.DataInputStream; 8 import java.io.DataOutputStream; 9 import java.io.IOException; 10 11 /** 12 * 数据流: 13 * 1、写出后读取 14 * 2、读取的顺序与写出保持一致 15 * 16 * DataOutputStream 17 * DataInputStream 18 * @author liuzeyu12a 19 * 20 */ 21 public class DataTest { 22 23 public static void main(String[] args) throws IOException { 24 //写出 25 ByteArrayOutputStream baos =new ByteArrayOutputStream(); 26 DataOutputStream dos =new DataOutputStream(new BufferedOutputStream(baos)); 27 //操作数据类型 +数据 28 dos.writeUTF("编码辛酸泪"); 29 dos.writeInt(18); 30 dos.writeBoolean(false); 31 dos.writeChar('a'); 32 dos.flush(); 33 byte[] datas =baos.toByteArray(); 34 System.out.println(datas.length); 35 //读取 36 DataInputStream dis =new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas))); 37 //顺序与写出一致 38 String msg = dis.readUTF(); 39 int age = dis.readInt(); 40 boolean flag = dis.readBoolean(); 41 char ch = dis.readChar(); 42 System.out.println(flag); 43 } 44 45 }
2、对象流(ObjectInputStream/ObjectOutputStream)
(对象的序列化与反序列化)
java.io
类 ObjectInputStream
java.lang.Object
继承者
java.io.InputStream
继承者
java.io.ObjectInputStream
public class ObjectInputStream
extends InputStream
implements ObjectInput, ObjectStreamConstants
ObjectInputStream
(1)ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
(2)只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。
(3)readObject
方法用于从流读取对象。应该使用 Java 的安全强制转换来获取所需的类型。在 Java 中,字符串和数组都是对象,所以在序列化期间将其视为对象。读取时,需要将其强制转换为期望的类型。
ObjectOutputStream的继承树与ObjectOutputStream类似
public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants
ObjectOutputStream
(1)ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。只能使用 ObjectInputStream 读取(重构)对象。
(2)只能将支持 java.io.Serializable 接口的对象写入流中。
(3)writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。
构造方法:ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
我们对外提供一个类Employee 用于被序列化和反序列化
代码:
1 //javabean 封装数据 2 class Employee implements java.io.Serializable{ 3 private transient String name; //该数据不需要序列化 4 private double salary; 5 public Employee() { 6 } 7 public Employee(String name, double salary) { 8 this.name = name; 9 this.salary = salary; 10 } 11 public String getName() { 12 return name; 13 } 14 public void setName(String name) { 15 this.name = name; 16 } 17 public double getSalary() { 18 return salary; 19 } 20 public void setSalary(double salary) { 21 this.salary = salary; 22 } 23 24 }
操作这个类:
1 package com.sxt.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.ByteArrayInputStream; 6 import java.io.ByteArrayOutputStream; 7 import java.io.IOException; 8 import java.io.ObjectInputStream; 9 import java.io.ObjectOutputStream; 10 import java.util.Date; 11 12 /** 13 * 对象流: 14 * 1、写出后读取 15 * 2、读取的顺序与写出保持一致 16 * 3、不是所有的对象都可以序列化Serializable 17 * 18 * ObjectOutputStream 19 * ObjectInputStream 20 * @author liuzeyu 21 * 22 */ 23 public class ObjectTest { 24 25 public static void main(String[] args) throws IOException, ClassNotFoundException { 26 27 //写出 -->序列化 28 ByteArrayOutputStream baos =new ByteArrayOutputStream(); 29 ObjectOutputStream oos =new ObjectOutputStream(new BufferedOutputStream(baos)); 30 //操作数据类型 +数据 31 oos.writeUTF("编码辛酸泪"); 32 oos.writeInt(18); 33 oos.writeBoolean(false); 34 oos.writeChar('a'); 35 //对象 36 oos.writeObject("谁解其中味"); 37 oos.writeObject(new Date()); 38 Employee emp =new Employee("马云",400); 39 oos.writeObject(emp); 40 oos.flush(); 41 byte[] datas =baos.toByteArray(); 42 System.out.println(datas.length); 43 44 //读取 -->反序列化 45 ObjectInputStream ois =new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(datas))); 46 //顺序与写出一致 47 String msg = ois.readUTF(); 48 int age = ois.readInt(); 49 boolean flag = ois.readBoolean(); 50 char ch = ois.readChar(); 51 System.out.println(flag); 52 //对象的数据还原 53 Object str = ois.readObject(); 54 Object date = ois.readObject(); 55 Object employee = ois.readObject(); 56 57 if(str instanceof String) { 58 String strObj = (String) str; 59 System.out.println(strObj); 60 } 61 if(date instanceof Date) { 62 Date dateObj = (Date) date; 63 System.out.println(dateObj); 64 } 65 if(employee instanceof Employee) { 66 Employee empObj = (Employee) employee; 67 System.out.println(empObj.getName()+"-->"+empObj.getSalary()); 68 } 69 70 } 71 72 }
其中对象流即可以操作基本数据类型,类似于数据流。也可以操作对象-->写出的过程称为类序列化,读取的过程称为反序列化。
这个时候时间对象的数据存入内存中,当然我们也可以存入到文件中。
见代码:
1 package com.sxt.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.FileInputStream; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.ObjectInputStream; 9 import java.io.ObjectOutputStream; 10 import java.util.Date; 11 12 /** 13 * 对象流: 1、写出后读取 2、读取的顺序与写出保持一致 3、不是所有的对象都可以序列化Serializable 14 * 15 * ObjectOutputStream ObjectInputStream 16 * 17 * @author liuzeyu12a 18 * 19 */ 20 public class ObjectTest02 { 21 22 public static void main(String[] args) throws IOException, ClassNotFoundException { 23 // 写出 -->序列化 24 ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("obj.ser"))); 25 // 操作数据类型 +数据 26 oos.writeUTF("编码辛酸泪"); 27 oos.writeInt(18); 28 oos.writeBoolean(false); 29 oos.writeChar('a'); 30 // 对象 31 oos.writeObject("谁解其中味"); 32 oos.writeObject(new Date()); 33 Employee emp = new Employee("马云", 400); 34 oos.writeObject(emp); 35 oos.flush(); 36 oos.close(); 37 38 // 读取 -->反序列化 39 ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("obj.ser"))); 40 // 顺序与写出一致 41 String msg = ois.readUTF(); 42 int age = ois.readInt(); 43 boolean flag = ois.readBoolean(); 44 char ch = ois.readChar(); 45 System.out.println(flag); 46 47 // 对象的数据还原 48 Object str = ois.readObject(); 49 Object date = ois.readObject(); 50 Object employee = ois.readObject(); 51 52 if (str instanceof String) { 53 String strObj = (String) str; 54 System.out.println(strObj); 55 } 56 if (date instanceof Date) { 57 Date dateObj = (Date) date; 58 System.out.println(dateObj); 59 } 60 if (employee instanceof Employee) { 61 Employee empObj = (Employee) employee; 62 System.out.println(empObj.getName() + "-->" + empObj.getSalary()); 63 } 64 ois.close(); 65 } 66 }
3、打印流PrintWriter和PrintStream
public class PrintWriter extends Writer
(1)向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream
中的所有 print 方法。不能输出字节,但是可以输出其他任意类型。
(2)与 PrintStream
类不同,如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。这些方法使用平台自有的行分隔符概念,而不是换行符。
(3)此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常。客户端可能会查询调用 checkError()
是否出现错误。
1 import java.io.FileWriter; 2 import java.io.IOException; 3 import java.io.PrintWriter; 4 /** 5 * 注意:创建FileWriter对象时boolean参数表示是否追加; 6 * 而创建打印流对象时boolean参数表示是否自动刷新 7 */ 8 public class PrintWriterDemo { 9 public static void main(String[] args) throws IOException { 10 //PrintWriter pw=new PrintWriter("print.txt"); 11 PrintWriter pw=new PrintWriter(new FileWriter("print.txt"),true); 12 pw.write("测试打印流"); 13 pw.println("此句之后换行"); 14 pw.println("特有功能:自动换行和自动刷新"); 15 pw.println("利用构造器设置自动刷新"); 16 pw.close(); 17 } 18 }
public class PrintStream
extends FilterOutputStream
implements Appendable, Closeable
(1)PrintStream
为其他输出流添加了功能(增加了很多打印方法),使它们能够方便地打印各种数据值
表示形式(例如:希望写一个整数,到目的地整数的表现形式不变。字节流的write方法只将一个整数的最低字节写入到目的地,
比如写fos.write(97),到目的地(记事本打开文件)会变成字符'a',
需要手动转换:fos.write(Integer.toString(97).getBytes());而采用PrintStream:ps.print(97),则可以保证数据的表现形式)。
1 //PrintStream的print方法
2 public void print(int i) {
3 write(String.valueOf(i));
4 }
(2)与其他输出流不同,PrintStream
永远不会抛出 IOException
;而是,异常情况仅设置可通过 checkError
方法测试的内部标志。
另外,为了自动刷新,可以创建一个 PrintStream
;这意味着可在写入 byte 数组之后自动调用 flush
方法,可调用其中一个 println
方法,或写入一个换行符或字节 ('\n'
)。
(3)PrintStream
打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter
类。
使用字节打印流复制文本文件:
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.PrintStream; 5 6 public class PrintStreamDemo { 7 public static void main(String[] args) throws IOException { 8 BufferedReader br=new BufferedReader(new FileReader("copy.java")); 9 PrintStream ps=new PrintStream("printcopy2.java"); 10 String line; 11 while((line=br.readLine())!=null) { 12 ps.println(line); 13 } 14 br.close(); 15 ps.close(); 16 } 17 } 18
PrintStream 的其它操作
1 package io深入学习; 2 3 import java.io.BufferedOutputStream; 4 import java.io.FileDescriptor; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.PrintStream; 8 9 public class PrintStream1 { 10 11 public static void main(String[] args) throws FileNotFoundException { 12 13 PrintStream ps = System.out; //将System.out赋值给ps对象 14 ps.println("我是谁???"); 15 ps.print(false); 16 17 //创建文件输出流以写入由指定的 File对象表示的文件。 18 ps = new PrintStream( 19 new BufferedOutputStream( 20 new FileOutputStream("print.txt")),true); 21 ps.print("这是打印流..."); 22 ps.println("打印到文件里的"); 23 ps.flush(); //确记要flush 24 25 System.setOut(ps);//重定向到文件 26 System.out.println("changeing"); 27 ps.flush(); //将把"change" 输出到文件里 28 29 //重定向回控制台 30 ps = new PrintStream( 31 new BufferedOutputStream( 32 new FileOutputStream(FileDescriptor.out)),true); 33 System.setOut(ps); 34 System.out.println("我又回来控制台了..."); 35 } 36 37 }
3、RandomAccessFile文件随机读写类
java.lang.Object
继承
java.io.RandomAccessFile
public class RandomAccessFile
extends Object
implements DataOutput, DataInput, Closeable
常用的构造方法:
public RandomAccessFile(File file,
String mode)
throws FileNotFoundException
mode 参数指定用以打开文件的访问模式。允许的值及其含意为:
值
含意
"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException
。"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 "rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 "rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
该类对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:
- 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。
- 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)
通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出EOFException
(是一种IOException
)。
如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出IOException
,而不是EOFException
。
需要特别指出的是,如果流已被关闭,则可能抛出IOException
。
注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。
1 package io深入学习; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.RandomAccessFile; 6 7 public class RAccessFile { 8 9 public static void main(String[] args) throws IOException{ 10 test03(); 11 12 } 13 14 //自定起始内容,读取剩余内容 15 public static void test01() throws IOException { 16 RandomAccessFile raf = new RandomAccessFile(new File("Copy.java"),"rw"); 17 //从第二个位置开始访问文件 18 raf.seek(2); 19 int temp=0; 20 byte [] flush = new byte[1024]; 21 while((temp = raf.read(flush))!=-1) { 22 System.out.print(new String(flush,0,temp)); 23 } 24 } 25 26 //分块思想:起始和实际大小 27 public static void test02() throws IOException { 28 RandomAccessFile raf = new RandomAccessFile(new File("Copy.java"),"rw"); 29 int actualSize = 1026; 30 int pos = 2; 31 int temp =0; 32 raf.seek(pos); 33 byte[] flush = new byte[1024]; 34 while((temp = raf.read(flush))!=-1) { 35 if(actualSize > temp) {//1026>1024 故读取1024个字节 36 System.out.println(new String(flush,0,temp)); 37 actualSize -=temp; 38 }else { //读取剩下的字节数 39 System.out.println(new String(flush,0,actualSize)); 40 break; 41 } 42 } 43 } 44 45 46 //分几块?每块大小? 47 public static void test03() throws IOException { 48 long bPos = 2; 49 File src = new File("Copy.java"); 50 51 long blockSize = 100; 52 long len = src.length(); 53 long actualSize = blockSize>len?len:blockSize; 54 System.out.println("文件大小:"+len); 55 int size = (int) Math.ceil(((1.0*len)/blockSize)); //转为double并向上取整 56 System.out.println("块数"+size); 57 for(int i = 0 ;i <size;i++) { 58 bPos = i*blockSize; 59 if(i == size-1) { //最后一块 60 actualSize = len; 61 }else { 62 actualSize = blockSize; 63 len -=actualSize; 64 } 65 System.out.println(i+"-->"+bPos +"-->"+actualSize); 66 split(i,bPos,actualSize); 67 } 68 } 69 70 //分块思想:起始和实际大小 71 public static void split(int i,long bPos,long actualSize) throws IOException { 72 RandomAccessFile raf = new RandomAccessFile(new File("Copy.java"),"rw"); 73 RandomAccessFile raf2 = new RandomAccessFile(new File("dest/"+i+"Copy.java"),"rw"); 74 int temp =0; 75 raf.seek(bPos); 76 byte[] flush = new byte[100]; 77 while((temp = raf.read(flush))!=-1) { 78 if(actualSize > temp) { //1026>1024 故读取1024个字节 79 System.out.println(new String(flush,0,temp)); 80 actualSize -=temp; 81 raf2.write(flush,0,temp); 82 }else { //读取剩下的字节数 83 System.out.println(new String(flush,0,(int)actualSize)); 84 raf2.write(flush,0,(int)actualSize); 85 break; 86 } 87 } 88 } 89 }
代码重新优化
1 package com.sxt.io; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.RandomAccessFile; 6 7 /** 8 * 随机读取和写入流 RandomAccessFile 9 * @author liuzeyu12a 10 * 11 */ 12 public class RandTest02 { 13 14 public static void main(String[] args) throws IOException { 15 //分多少块 16 File src = new File("p.png"); 17 //总长度 18 long len = src.length(); 19 //每块大小 20 int blockSize =1024; 21 //块数: 多少块 22 int size =(int) Math.ceil(len*1.0/blockSize); 23 System.out.println(size); 24 25 //起始位置和实际大小 26 int beginPos = 0; 27 int actualSize = (int)(blockSize>len?len:blockSize); 28 for(int i=0;i<size;i++) { 29 beginPos = i*blockSize; 30 if(i==size-1) { //最后一块 31 actualSize = (int)len; 32 }else { 33 actualSize = blockSize; 34 len -=actualSize; //剩余量 35 } 36 System.out.println(i+"-->"+beginPos +"-->"+actualSize); 37 split(i,beginPos,actualSize); 38 } 39 40 } 41 /** 42 * 指定第i块的起始位置 和实际长度 43 * @param i 44 * @param beginPos 45 * @param actualSize 46 * @throws IOException 47 */ 48 public static void split(int i,int beginPos,int actualSize ) throws IOException { 49 RandomAccessFile raf =new RandomAccessFile(new File("p.png"),"r"); 50 RandomAccessFile raf2 =new RandomAccessFile(new File("dest/"+i+"p.png"),"rw"); 51 //随机读取 52 raf.seek(beginPos); 53 //读取 54 //3、操作 (分段读取) 55 byte[] flush = new byte[1024]; //缓冲容器 56 int len = -1; //接收长度 57 while((len=raf.read(flush))!=-1) { 58 if(actualSize>len) { //获取本次读取的所有内容 59 raf2.write(flush, 0, len); 60 actualSize -=len; 61 }else { 62 raf2.write(flush, 0, actualSize); 63 break; 64 } 65 } 66 raf2.close(); 67 raf.close(); 68 } 69 70 71 }
3、序列流SequenceInputStream和SequenceOutputStream
表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,
直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
构造方法:
public SequenceInputStream(Enumeration<? extends InputStream> e)
参数是一个枚举类型
通过记住参数来初始化新创建的 SequenceInputStream
,该参数必须是生成运行时类型为 InputStream
对象的 Enumeration
型参数。
将按顺序读取由该枚举生成的输入流,以提供从此 SequenceInputStream
读取的字节。在用尽枚举中的每个输入流之后,将通过调用该流的 close
方法将其关闭。
文件的切割与合并:
1 package com.sxt.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.io.OutputStream; 11 import java.io.RandomAccessFile; 12 import java.io.SequenceInputStream; 13 import java.util.ArrayList; 14 import java.util.List; 15 import java.util.Vector; 16 17 /** 18 * 面向对象思想封装 分割 19 * @author liuzeyu12a 20 * 21 */ 22 public class SplitFile { 23 //源头 24 private File src; 25 //目的地(文件夹) 26 private String destDir; 27 //所有分割后的文件存储路径 28 private List<String> destPaths; 29 //每块大小 30 private int blockSize; 31 //块数: 多少块 32 private int size; 33 34 public SplitFile(String srcPath,String destDir) { 35 this(srcPath,destDir,1024); 36 } 37 public SplitFile(String srcPath,String destDir,int blockSize) { 38 this.src =new File(srcPath); 39 this.destDir =destDir; 40 this.blockSize =blockSize; 41 this.destPaths =new ArrayList<String>(); 42 43 //初始化 44 init(); 45 } 46 //初始化 47 private void init() { 48 //总长度 49 long len = this.src.length(); 50 //块数: 多少块 51 this.size =(int) Math.ceil(len*1.0/blockSize); 52 //路径 53 for(int i=0;i<size;i++) { 54 this.destPaths.add(this.destDir +"/"+i+"-"+this.src.getName()); 55 } 56 } 57 /** 58 * 分割 59 * 1、计算每一块的起始位置及大小 60 * 2、分割 61 * @throws IOException 62 */ 63 public void split() throws IOException { 64 //总长度 65 long len = src.length(); 66 //起始位置和实际大小 67 int beginPos = 0; 68 int actualSize = (int)(blockSize>len?len:blockSize); 69 for(int i=0;i<size;i++) { 70 beginPos = i*blockSize; 71 if(i==size-1) { //最后一块 72 actualSize = (int)len; 73 }else { 74 actualSize = blockSize; 75 len -=actualSize; //剩余量 76 } 77 splitDetail(i,beginPos,actualSize); 78 } 79 } 80 /** 81 * 指定第i块的起始位置 和实际长度 82 * @param i 83 * @param beginPos 84 * @param actualSize 85 * @throws IOException 86 */ 87 private void splitDetail(int i,int beginPos,int actualSize ) throws IOException { 88 RandomAccessFile raf =new RandomAccessFile(this.src,"r"); 89 RandomAccessFile raf2 =new RandomAccessFile(this.destPaths.get(i),"rw"); 90 //随机读取 91 raf.seek(beginPos); 92 //读取 93 //3、操作 (分段读取) 94 byte[] flush = new byte[1024]; //缓冲容器 95 int len = -1; //接收长度 96 while((len=raf.read(flush))!=-1) { 97 if(actualSize>len) { //获取本次读取的所有内容 98 raf2.write(flush, 0, len); 99 actualSize -=len; 100 }else { 101 raf2.write(flush, 0, actualSize); 102 break; 103 } 104 } 105 raf2.close(); 106 raf.close(); 107 } 108 /** 109 * 文件的合并 110 * @throws IOException 111 */ 112 public void merge(String destPath) throws IOException { 113 //输出流 114 OutputStream os =new BufferedOutputStream( new FileOutputStream(destPath,true)); 115 Vector<InputStream> vi=new Vector<InputStream>(); 116 SequenceInputStream sis =null; 117 //输入流 118 for(int i=0;i<destPaths.size();i++) { 119 vi.add(new BufferedInputStream(new FileInputStream(destPaths.get(i)))); 120 } 121 sis =new SequenceInputStream(vi.elements()); 122 //拷贝 123 //3、操作 (分段读取) 124 byte[] flush = new byte[1024]; //缓冲容器 125 int len = -1; //接收长度 126 while((len=sis.read(flush))!=-1) { 127 os.write(flush,0,len); //分段写出 128 } 129 os.flush(); 130 sis.close(); 131 os.close(); 132 } 133 public static void main(String[] args) throws IOException { 134 SplitFile sf = new SplitFile("src/com/sxt/io/SplitFile.java","dest") ; 135 sf.split(); 136 sf.merge("aaa.java"); 137 } 138 }
*总结一下IO流使用的规律:
再扔个图比较好查看
(1)明确要操作的数据是数据源还是数据目的(要读还是要写)
源:InputStream Reader
目的:OutputStream Writer
(2)明确要操作的设备上的数据是字节还是文本
源:
字节:InputStream
文本:Reader
目的:
字节:OutputStream
文本:Writer
(3)明确数据所在的具体设备
源设备:
硬盘:文件 File开头
内存:数组,字符串 ByteArrayInputStream/ByteArrayOutputStream
键盘:System.in
网络:Socket
目的设备:
硬盘:文件 File开头
内存:数组,字符串 ByteArrayInputStream/ByteArrayOutputStream
屏幕:System.out
网络:Socket
(4)明确是否需要额外功能?
需要转换——转换流 InputStreamReader OutputStreamWriter
需要高效——缓冲流Bufferedxxx
多个源——序列流 SequenceInputStream
对象序列化——ObjectInputStream,ObjectOutputStream(数据的存储用的)
保证数据的输出形式——打印流PrintStream Printwriter
操作基本数据,保证字节原样性——DataOutputStream,DataInputStream
参考附上大佬的博客:https://www.cnblogs.com/hopeyes/p/9736642.html(崇拜大佬可以把博客写的这么棒,总结的面面俱到)