• 其它几个常用的IO辅助流


    常用的其它流

    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 }
    View Code

    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 }
    View Code
    其中对象流即可以操作基本数据类型,类似于数据流。也可以操作对象-->写出的过程称为类序列化,读取的过程称为反序列化。
    这个时候时间对象的数据存入内存中,当然我们也可以存入到文件中。
    见代码:
     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 }
    View Code
    
    
    
    

    3、打印流PrintWriter和PrintStream

    public class PrintWriter extends Writer

    (1)向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。不能输出字节,但是可以输出其他任意类型。

    (2)与 PrintStream 类不同,如果启用了自动刷新,则只有在调用 printlnprintf 或 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 方法,或写入一个换行符或字节 (' ')。
    (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 }
    View Code

    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",还要求对文件内容的每个更新都同步写入到底层存储设备。

    该类对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:

    1. 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。
    2. 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(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 }
    View Code

    代码重新优化

     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 }
    View Code

    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 }
    View Code
    
    

     *总结一下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(崇拜大佬可以把博客写的这么棒,总结的面面俱到)
  • 相关阅读:
    移动端疫情展示
    第四周学习总结
    构建之法阅读笔记二
    第三周学习总结
    AJAX学习篇
    jQuery学习篇
    软件工程开课第二周——介绍篇
    【Spring】DispatcherServlet的启动和初始化
    【设计模式】模板方法模式小解
    【Mybatis】MyBatis调用带有返回结果、output参数的存储过程上与ibatis的区别
  • 原文地址:https://www.cnblogs.com/liuzeyu12a/p/10398704.html
Copyright © 2020-2023  润新知