IO技术学习笔记

   IO技术核心:

三口:Closeable,Flushable,Serializable

五类:File,InputStream,OutputStream,Reader,Writer

  ApI阅读方法:

1.看继承体系,简短说明。

2.看构造器,若无构造器,则为工具类或具有静态方法。

3.看方法,重点关注方法的名字与形参,及返回形式,是否为静态方法。

  流的概念:

按流的方向分类:

      1. 输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。

      2. 输出流:数据流向是程序到目的地(以OutPutStream、Writer结尾的流)。

          程序相当于是一个中介(中心),以程序为基础判断是输入流(读)还是输出流(写)。

按处理的数据单元分类:

      1. 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。

      2. 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。

字符流的底层还是字节流,因为计算机只认识二进制数据。字符集是二者转化的“字典”

按处理对象不同分类:

      1. 节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等,名字中带着File/Byte

      2.  处理流:(基于节点流)不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。

      节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。

  File类:

Java无法直接操纵文件,因此file类是抽象的,表示java与文件之间的联系,实际上文件可能不存在。

File.separator:分隔符

路径的3种书写方式:1."C:\\Users\\Dexin\\Desktop\\java练习\\javaexercise\\chapter10\\1.png"(必须是双杠)

                                  2."C:"+File.separator+"Users"+File.separator+"Dexin"+File.separator+"Desktop"+File.separator+"java练

                                      习"+File.separator+"javaexercise"+File.separator+"chapter10"+File.separator+"1.png"

                                  3."C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/1.png"(推荐)

利用File类的多样构造方法来构造对象:

1.File(path)

例:String path = "C:\\Users\\Dexin\\Desktop\\java练习\\javaexercise\\chapter10\\1.png";

       File src1 =new File(path);

2.File(String parent, String child)

例:File src2 = new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10","1.png");

       File src3 = new File("C:/Users/Dexin","Desktop/java练习/javaexercise/chapter10/1.png");

3.File(File parent, String child)

例:File src4 = new File(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10"),"1.png");

带盘符的成为绝对路径,不带的成为相对路径。

可用getAbsolutePath()方法获得绝对路径。

 File类相关方法:

1.getName():获取文件名称

   getPath():获取文件路径,给的是什么路径就返回什么路径

   getAbsolutePath():获取文件绝对路径

   getParent():获取父路径,将给的路径去除文件名

2.exists()文件是否存在

   isFile()判断是否是文件

   isDirectory()判断是否是文件夹

3.length()获取文件长度,若文件不存在或不是文件,返回0(我测试的时候文件夹返回4096)

4.createNewFile()根据File类对象创建实际文件(不存在才能创建)

   delete()删除实际文件(存在实际文件才能删除)

 几个重要的小练习:

1.用递归的方法分级列出文件夹下的文件(常用类中已做)

2.用递归的方法计算文件夹的大小。重点在于如下方法:

3.用自定义对象的方式计算文件夹的大小。在创建该类的对象时,已经创建了指定path的File类对象,并自动执行了count方法。只要用get方法获取length即可。(count方法与上面相同,略写)

4.用自定义对象的方式计数指定文件夹中的文件与文件夹个数。

在3的基础之上,定义filesize与dirsize,并分别写getters。修改count方法,若为文件,filesize++,文件夹则dirsize++。最后在main函数中打印getFilesize与getDirsize即可。

  字符集:

相当于字节与字符转换的字典。

常用的字符集:1.GBK 默认字符集,中文2个字节,英文1个

                         2.UTF-16LE 定长,中英文均2个字节

                         3.UTF-8 变长,中文3个字节,英文1一个

编码格式:byte[ ] 字节对象名称 = 指定字符串名称.getBytes("字符集名称");

                  可用length()方法查看字节对象的长度

解码格式:String 字符串名称=new String(字节对象名称,起始位,长度,"字符集名称");

乱码可能的原因:1.字节数不够

                             2.字符集不统一

InputStream:字节输入流的父类,常用方法read()(读取字节),close()(关闭流,释放相关系统资源)

OutputStream:字节输出流的父类,有Flushable接口(刷新),常用方法write(int)flush()close()

Reader:字符输入流的父类,有Readable接口,常用方法read()close()

Writer:字符输出流的父类,有Flushable接口(刷新),Appendble接口(从尾部追加),常用方法write(String)flush()close()

IO程序经典步骤:1.确定数据源 2.确定流 3.读/写操作 4.释放系统资源

  使用FileInputStream读取字节:

1.int read():逐个字节读取,返回的就是字节代码,(char)强制转型即可查看。

    File src = new File("d:/a.text");//确定数据源头
    InputStream is =null;
    try {
        is = new FileInputStream(src);
        int temp;
            while((temp=is.read())!=-1) {
                System.out.println((char)temp);
            }
        }
         catch (FileNotFoundException e) { 
            e.printStackTrace();
         }
         catch (IOException e) {
            e.printStackTrace();
         }finally {
        try {
            if(null!=is) {
            is.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
View Code

2.int read(byte [ ] 数组名称):将字节按指定长度缓存在数组中,返回的是实际读取的字节数(若读完则返回-1),通过解码才能查看。

操作部分步骤总结:建立缓存数组byte[ ],并指定规格(一般为1024的倍数)。定义实际读入长度(用来判断是否读完)。写一个while循环,用read()方法将输入流对象中的内容读到缓存数组中。若读完(length为-1),则我们得到一组字节数据。接着用String方法进行解码,将得到的字符数据存入字符串中。然后可以打印这个字符串。

 1         File src =new File("d:/a.text");
 2         InputStream is = null;
 3         try {
 4              is = new FileInputStream(src); 
 5             byte [] flush = new byte[1024];//一次性缓存1024个字节在flush中
 6             int length;
 7                while((length=is.read(flush))!=-1) { 
 8                     String str = new String(flush,0,length);//解码
 9                     System.out.println(str);
10             }
11         }
12              catch (FileNotFoundException e) {
13                 e.printStackTrace();
14              } 
15              catch (IOException e) {
16                 e.printStackTrace();
17              }finally {
18                  if(null!=is) {
19                      try {
20                         is.close();
21                     } catch (IOException e) {
22                         e.printStackTrace();
23                     }
24                  }
25              }
View Code

 注意:用read()方法读到程序里的是字节  

  使用FileOutputStream写字节:

一开始指定的数据源可以不存在,创建输出流对象时可指定写的方法(true附加,false覆盖)。在写操作之后要用flush()方法刷新一下。

操作部分步骤总结:指定一个字符串作为写的内容。将其用getBytes()方法编码,将编码后的字节并存放在一个byte[ ]数组中。用write()方法将字节数组写到输出流对象中,最后flush()刷新一些即可。

 1         File src = new File("d:/b.text");//可以不存在
 2         OutputStream os = null;
 3         try {
 4             os = new FileOutputStream(src,true);//true表示追加写,false表示覆盖写
 5             String msg = "I love you"; //指定写入的语句
 6             byte[]data=msg.getBytes();//编码
 7             os.write(data,0,data.length);//将编码完的字节数组写到os流对象中
 8             os.flush();//刷新,这是个好习惯
 9         }
10             catch (FileNotFoundException e) {
11                 e.printStackTrace();
12             }
13             catch (IOException e) {
14                 e.printStackTrace();
15             }finally {
16                 if(null!=os) {
17                 try {
18                     os.close();
19                 } catch (IOException e) {
20                     e.printStackTrace();
21                 }
22                 }
23             }
View Code

注意:用write()方法写的内容也必须是字节。   

  FileInputStream,FileInputStream综合运用 拷贝文件:

以程序为中介,先读入,后写出,完成拷贝。

注意最后释放系统资源时,先打开的流对象后关闭。

 1 public static void copy(String srcpath,String destpath) {
 2     File src = new File(srcpath);
 3     File dest = new File(destpath);
 4     InputStream is =null;
 5     OutputStream os = null;
 6     try {
 7         is = new FileInputStream(src);
 8         os = new FileOutputStream(dest);
 9         byte[]flush=new byte[1024];
10         int length=-1;
11             while((length=is.read(flush))!=-1) {//
12                 os.write(flush,0,length);//
13             } 
14         os.flush();//刷新
15     } catch (FileNotFoundException e) {
16       e.printStackTrace();
17       }
18       catch (IOException e) {
19       e.printStackTrace();
20       }finally {
21           if(null!=os) {
22               try {
23                 os.close();
24               } catch (IOException e) {
25                 e.printStackTrace();
26                 }
27           }
28           if(null!=is) {
29               try { 
30                 is.close();  //先打开的后关闭
31               } catch (IOException e) {  
32                 e.printStackTrace();
33                 }
34           }
35          
36       }
37         
38 }
View Code

   使用FileReader读取字符:

创建缓存字符数组char[ ],并指定规格。定义实际读入长度(用来判断是否读完)。写一个while循环,用read()方法将输入流对象中的内容读到缓存字符数组中。若读完(length为-1),则我们得到一组字符数据,可以直接打印这个数组。这个过程中没有字节的参与,均为字符。

 1     File src = new File("d:/a.text");
 2     Reader rd =null;
 3     try {
 4         rd = new FileReader(src);
 5         char[]flush = new char[1024];
 6         int length;
 7             while((length=rd.read(flush))!=-1) {
 8                 System.out.println(flush);
 9             }
10     }
11         catch (FileNotFoundException e) {
12             e.printStackTrace();
13         }
14         catch (IOException e) {
15             e.printStackTrace();
16         }finally {
17             if(null!=rd){
18                 try {
19                     rd.close();
20                 } catch (IOException e) {
21                     e.printStackTrace();
22                 }
23             }
24         }
View Code

  使用FileWriter写字符:

方法1:指定一个字符串。用toCharArray()方法将字符串存在char[ ]数组中。用write方法将数组中的内容写入流对象中。

方法2:指定一个字符串。直接用write()方法将字符串写入流对象中。

方法3:直接用append()方法将字符串写入流对象中。

这个过程中没有字节的参与,均为字符。

 1     File dest = new File("d:/a.text");
 2     Writer wt =null;
 3     try {
 4         wt = new FileWriter(dest);
 5         //写法1
 6         //String str = "努力学习";
 7         //char[] data = str.toCharArray();
 8         //wt.write(data,0,data.length);
 9         //写法2
10         //String str = "更加努力学习";
11         //wt.write(str);
12         //写法3
13         wt.append("每天").append("都要").append("努力学习");
14         wt.flush();
15     } catch (IOException e) {
16         e.printStackTrace();
17     }finally {
18         if(null!=wt) {
19             try {
20                 wt.close();
21             } catch (IOException e) {
22                 e.printStackTrace();
23             }
24         }
25     }
View Code

  使用ByteArrayInputStream读取字节数组:

与FileInputStream的不同之处在于,它的数据源是一个字节数组(指定字符串后,用getBytes()方法获得)。Byte类的流都不需要释放资源。

 1         byte[] src = "I love you so much".getBytes();//数据源是一个字节数组
 2     InputStream is = new ByteArrayInputStream(src);
 3     byte[]flush = new byte[20];
 4     int length;
 5     try {
 6         while((length=is.read(flush))!=-1) {
 7             String str = new String(flush,0,length);
 8             System.out.println(str);
 9         }
10     } catch (IOException e) {
11         e.printStackTrace();
12     }
13 }
View Code

  使用ByteArrayOutputStream向内存写一段字节:

不需要指定目的地,创建一个字节数组置为null即可。指定一段字符串后,用getBytes()方法编码放入字节数组中,再写入流中。

最后我们需要通过toByteArray()方法将流中的字节放入目的地数组中,才可以打印查看。因为这是ByteArrayOutputStream新增的方法,因此一开始创建流对象时不可以使用多态。

 1     byte [] dest = null;//不指定目的地
 2     try {
 3         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 4         String str = "I love you";
 5         byte[] data=str.getBytes();//编码
 6         baos.write(data,0,data.length);//将编码完的字节数组写入流中
 7         baos.flush();
 8         dest=baos.toByteArray();
 9         System.out.println(dest.length);
10         System.out.println(new String(dest,0,dest.length));
11     }     catch (IOException e) {
12           e.printStackTrace();
13           }
View Code

   释放资源程序的优化:

1.普通封装为:public static void close(Inputstream is,OutputStream os)

作用是释放了关于这两个流的资源。

2.使用Closeable接口关闭多个流的封装

 1 public static void close(Closeable...ios) {
 2     for(Closeable io:ios) {
 3             try {
 4                 if(null!=io) {
 5                 io.close();
 6                 }
 7             }
 8                 catch (IOException e) {
 9                 e.printStackTrace();
10                 }    
11     }
12 }
View Code

3.try with resource

只须去掉finally所有内容,在try后添加(),括号中写需要释放资源的流即可,多个流用分号隔开,如:try (is;os)

   装饰器结构:

1.抽象组件:待装饰对象的类的接口。定义一个接口(饮料),其中定义一些方法(价格,信息)。

2.具体组件:待装饰对象的类(咖啡),是1的实现类。可以在其中定义私有信息(咖啡名称),并对1中所有方法提供实现(价格10元,信息输出咖啡名称)。

3.抽象装饰类:装饰对象的类的抽象类,也是1的实现类。相当于给了一个装饰方法的模板。先定义一个1的对象(饮料对象),并且传入构造方法,然后实现1中的方法,返回的是这里定义的对象调用的方法(this.饮料对象.价格/信息)。

4.具体装饰类:具体装饰物(牛奶,糖果),继承3。构造方法中传入3中定义的对象(饮料对象)。实现方法中返回3中调用方法并可作一定的操作(super.价格*4/信息“加入了牛奶”)

main函数中,创建一个具体组件的对象。加装饰时,先创建具体装饰类的对象,并传入具体组件对象的名称,就可以打印具体的方法了。

 1 public class DecorateDrink {
 2     public static void main(String[] args) {
 3         drink cf = new coffee();
 4         //加牛奶
 5         drink m = new milk(cf);
 6         System.out.println(m.info());
 7         System.out.println(m.cost());
 8         //加糖
 9         drink s = new sugar(cf);
10         System.out.println(s.info());
11         System.out.println(s.cost());
12         //混合
13         drink ms = new milk(cf);//加完牛奶
14         ms=new sugar(m);   //再加糖,成为ms
15         System.out.println(ms.info());
16         System.out.println(ms.cost());
17     }
18 }
19 //抽象组件
20 interface drink{  
21     double cost();
22     String info();
23 }
24 //具体组件
25 class coffee implements drink{
26     private String name = "原味咖啡";
27     public double cost() {
28         return 10;
29     }
30     public String info() {
31         return name;
32     }
33 }
34 //抽象装饰类
35 abstract class decorate implements drink{
36     private drink dk;
37     public decorate(drink dk) {
38         super();
39         this.dk = dk;
40     }
41     public double cost() {
42         return (this.dk.cost());
43     }
44     public String info() {
45         return (this.dk.info());
46     }
47 }
48 //具体装饰类1
49 class milk extends decorate{
50     public milk(drink dk) {
51         super(dk);
52     }
53     public double cost() {
54         return (super.cost()*4);
55     }
56     public String info() {
57         return (super.info()+"加入了牛奶");
58     }
59     
60 }
61 //具体装饰类2
62 class sugar extends decorate{
63     public sugar(drink dk) {
64         super(dk);
65     }
66     public double cost() {
67         return (super.cost()+5);
68     }
69     public String info() {
70         return (super.info()+"加入了糖");
71     }
72     
73 }
View Code

   BufferedInputStream&BufferedOutputStream:

作用是对字节流进行缓冲,提高效率。默认缓冲区为8k,可以自己设定。

简便使用格式为:InputStream 流名称 = new BufferedInputStream(new FileInputStream(文件对象名称));

                            OutputStream 流名称 = new BufferedOutputStream(new FileOutputStream(文件对象名称));

如果要释放流资源,应先释放里面的,再释放外面的,处理流也可以不释放。

  BufferedReader&BufferedWriter:

BufferedReader新方法:readLine()读一行字符,可以代替缓冲区

BufferedWriter新方法:newLine()可以代替换行。

由于有新方法,因此不能用多态。

注意使用try with resource来释放流资源。

以下是一个应用了BufferedReader与BufferedWriter的copy程序:

 1        File src = new File("d:/a.text");
 2        File dest = new File("d:/copy of a.text");
 3        try( BufferedReader bfr = new BufferedReader(new FileReader(src));
 4                BufferedWriter bfw = new BufferedWriter(new FileWriter(dest));) 
 5        {
 6           String line = null;
 7           while((line = bfr.readLine())!=null) {
 8               bfw.write(line);
 9               bfw.newLine();
10           }
11            bfw.flush();
12        } 
13        catch (FileNotFoundException e) {
14               e.printStackTrace();
15           }
16        catch (IOException e) {
17             e.printStackTrace();
18         }   
View Code

  InputStreamReader&OutputStreamWriter:

实现了将字节流转化成字符流

System.in是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符流BufferedReader特有的方法readLine(),但是经过观察会发现在创建BufferedReader的构造方法的参数必须是一个Reader对象,这时候我们的转换流InputStreamReader就派上用场了。

而System.out也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的write(String str)方法,所以我们要使用OutputStreamWriter将字节流转化为字符流。

 1     try (BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
 2          BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(System.out));){
 3          String msg = "";
 4               while(!msg.equals("exit")) {
 5                  msg=bfr.readLine();
 6                  bfw.write(msg);
 7                  bfw.newLine();
 8                  bfw.flush();    
 9               }
10     }
11     catch (IOException e) {
12         e.printStackTrace();
13     }
View Code
 1     try (BufferedReader bfr = new BufferedReader
 2             (new InputStreamReader
 3             (new URL("http://www.baidu.com").openStream(),"UTF-8"));
 4          BufferedWriter bfw = new BufferedWriter
 5             (new OutputStreamWriter
 6             (new FileOutputStream("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/baidu.html"),"UTF-8"));){
 7         String msg = "";
 8         while((msg=bfr.readLine())!=null) {
 9              bfw.write(msg);
10              bfw.newLine();
11              bfw.flush();    
12         }
13     } catch (UnsupportedEncodingException e) {
14         e.printStackTrace();
15     } catch (MalformedURLException e) {
16         e.printStackTrace();
17     } catch (IOException e) {
18         e.printStackTrace();
19     }
View Code

  DataInputStream&DataOutputStream:

数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型。

DataInputStream:从输入流中读取基本数据类型的数据

DataOutputStream:将基本数据类型的数据写入输出流

心得:任何类型的数据都可以通过toByteArray()方法转化为字节数组。

 1 ByteArrayOutputStream baos= new ByteArrayOutputStream();
 2     DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
 3     dos.writeUTF("努力学习");
 4     dos.writeInt(18);
 5     dos.writeBoolean(false);
 6     dos.writeChar('a');
 7     dos.flush();
 8     byte[] datas = baos.toByteArray();//转化为字节数组
 9     System.out.println(datas.length);
10     
11     DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));//读出基本类型
12     String msg = dis.readUTF();
13     int age = dis.readInt();
14     Boolean flag = dis.readBoolean();
15     char ch = dis.readChar();
View Code

此处忽略了异常的处理,可以直接throw。

  ObjectInputStream&ObjectOutputStream:

ObjectOutputStream:把Java对象转换为字节序列的过程称为对象的序列化。

ObjectInputStream:把字节序列恢复为Java对象的过程称为对象的反序列化。

与数据流用法类似(因为所有数据类型都是对象),需要先写出(序列化),再读入(反序列化)

不仅可以将八大基本数据类型的数据转化成字节序列后再读,也可以操作各种对象。

特别注意:

只有实现了Serializable接口的对象才能被序列化,java自带的类的对象一般都有。但是,在操作自定义类的对象时(javabean),一定要手动实现java.io.Serializable接口。若某些属性不想被序列化,可以加上transient关键字。

最后打印的时候,要先判断读入(反序列化)后的对象是不是指定类型的对象,若是,强制转型后打印

 1 public class ObjectStream {
 2 
 3     public static void main(String[] args) throws ClassNotFoundException, IOException {
 4         ByteArrayOutputStream baos= new ByteArrayOutputStream();
 5         ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(baos));
 6         oos.writeUTF("努力学习");
 7         oos.writeInt(18);
 8         oos.writeBoolean(false);
 9         oos.writeChar('a');
10         oos.writeObject("天天向上");
11         oos.writeObject(new Date());
12         employee emp = new employee("小明",30000);
13         oos.writeObject(emp);
14         oos.flush();
15         byte[] datas = baos.toByteArray();//转化为字节数组
16         System.out.println(datas.length);
17         
18         ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
19         String msg = ois.readUTF();
20         int age = ois.readInt();
21         Boolean flag = ois.readBoolean();
22         char ch = ois.readChar();
23         Object study = ois.readObject();
24         Object date = ois.readObject();
25         Object empp = ois.readObject();
26         
27         
28         if(flag instanceof Boolean) {
29             Boolean booleanObj =(Boolean)flag;
30             System.out.println(booleanObj);
31         }
32         if(study instanceof String) {
33             String strObj =(String)study;
34             System.out.println(strObj);
35         }
36         if(date instanceof Date) {
37             Date dateObj =(Date)date;
38             System.out.println(dateObj);
39         }
40         if(empp instanceof employee) {
41             employee strObj =(employee)empp;
42             System.out.println(strObj);
43         }
44     }
45 
46 }
47 
48 class employee implements java.io.Serializable{//一定要实现序列化接口
49     private String name;
50     private double salary;
51     public employee(String name, double salary) {
52         super();
53         this.name = name;
54         this.salary = salary;
55     }
56     public employee() {
57         
58     }
59     public String getName() {
60         return name;
61     }
62     public void setName(String name) {
63         this.name = name;
64     }
65     public double getSalary() {
66         return salary;
67     }
68     public void setSalary(double salary) {
69         this.salary = salary;
70     }
71     
72 }
View Code

  PrintStream:

打印流,方便打印。可通过setOut()方法来定向打印位置。

 1 PrintStream ps =System.out;
 2    ps.println("努力学习java");//写到控制台
 3    ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/print.txt")),true);//true即为自动刷新
 4      ps.println("坚持学习java");//写入指定文件
 5     //重定向输入端到指定文件
 6     System.setOut(ps);
 7     System.out.println("已重定向至指定文件");
 8      //重定向回控制台
 9     System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true));
10     System.out.println("已重定向回控制台");
View Code

  RandomAccessFile:

随机访问流。创建RandomAccessFile流对象后,可用seek()方法来设置从第几个元素开始访问。

  综合应用——分割文件:

SequenceInputStream可将多个输入流合并到一个容器中。

 1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.OutputStream;
 7 import java.io.RandomAccessFile;
 8 import java.io.SequenceInputStream;
 9 import java.util.ArrayList;
10 import java.util.List;
11 import java.util.Vector;
12 import java.io.BufferedInputStream;
13 import java.io.BufferedOutputStream;
14 
15 public class SplitFile {
16     private File src;  //源头文件
17     private String destDir; //目的地(文件夹)
18     private List <String> destPaths;//所有分割后的文件存储路径
19     private int blockSize; //每块大小
20     private int size;//块数
21     public SplitFile(String srcpath,String destDir, int blockSize) {
22         super();
23         this.src = new File(srcpath);//源文件地址
24         this.destDir = destDir;//目的地(文件夹)
25         this.blockSize = blockSize;//每块大小
26         this.destPaths=new ArrayList<String>();//所有分割后的文件存储路径
27         init();
28     }
29     //初始化:根据文件总长度与每块长度计算总块数,为分割后的文件命名
30     private void init() {
31            long length = this.src.length();  //文件总长度
32            this.size = (int)Math.ceil(length*1.0/blockSize);  //定义块数
33              for(int i=0;i<size;i++) {
34                 this.destPaths.add(this.destDir+ "/"+ i + "-"+ this.src.getName());
35             }
36         }
37     //分割方法:分情况处理每块的实际长度,再具体分割
38     public void split() throws IOException {
39         long length = src.length();  //文件总长度
40         int beginPos = 0;
41         int actualSize = (int)(blockSize>length?length:blockSize); //如果不足一块,则只取一次,实际长度即为总长度,否则按块取
42         for(int i=0;i<size;i++) {
43             beginPos=i*blockSize;
44             if(i==size-1) {//最后一块
45                 actualSize=(int)length;    
46             }else {
47                 actualSize=blockSize;
48                 length-=blockSize;
49             }
50             splitDetail(i,beginPos,actualSize);
51         }
52     }
53     //具体分割方法:从源文件中向目标地址分块写内容
54     private void splitDetail(int i,int beginPos,int actualSize) throws IOException {
55         RandomAccessFile raf = new RandomAccessFile(this.src,"r");
56         RandomAccessFile raf2 = new RandomAccessFile(this.destPaths.get(i),"rw");
57         raf.seek(beginPos);
58         byte[] flush = new byte[1024];
59         int length=-1;
60         while((length=raf.read(flush))!=-1) {
61             if(actualSize>length) {
62             raf2.write(flush,0,length);
63             actualSize-=length;
64         }else {
65             raf2.write(flush,0,actualSize);
66             break;
67         }
68         
69     }raf2.close();
70     raf.close();
71     }
72     //合并
73     public void merge(String destPath) throws IOException{
74         //输出流
75         OutputStream os = new BufferedOutputStream(new FileOutputStream(destPath,true));
76         Vector<InputStream>vi=new Vector<InputStream>();
77         SequenceInputStream sis = null;
78         //输入流
79         for(int i=0;i<destPaths.size();i++) {
80             vi.add(new BufferedInputStream(new FileInputStream(destPaths.get(i))));
81         }
82         sis=new SequenceInputStream(vi.elements());
83         byte [] flush = new byte[1024];//一次性缓存1024个字节在flush中
84         int length=-1;
85            while((length=sis.read(flush))!=-1) { 
86             os.write(flush,0,length);
87         }
88            os.flush();
89            sis.close();
90            os.close();
91     }
92     public static void main(String[] args) throws IOException {
93         SplitFile sf = new SplitFile("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/TestCopy.java","C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10",1024);
94         sf.split();
95         sf.merge("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/Fdx.java");
96     }
97 }
View Code

  CommosIO:

资源下载:http://commons.apache.org/proper/commons-io/download_io.cgi

下载Binaries中的commons-io-2.6-bin.zip。解压后,将commons-io-2.6.jar与commons-io-2.6-sources.jar文件拷贝到程序所在工程的一个新建文件夹下。将commons-io-2.6.jar添加至路径后,即可使用。若想查看源码,写出想查看的方法名,ctrl+单击方法名,将commons-io-2.6-sources.jar加入即可。

1.查看文件/文件夹的大小:FileUtils.sizeOf()方法

1 long length = FileUtils.sizeOf(new File("d:/a.text"));
2     System.out.println(length);
3     length = FileUtils.sizeOf(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10"));
4     System.out.println(length);
View Code

2.获取列表文件:listFiles()方法

 1 Collection <File> files= FileUtils.listFiles(new File("D:/PCGame"),
 2                 EmptyFileFilter.NOT_EMPTY,null);//只读一级文件
 3         for(File file:files) {
 4             System.out.println(file.getAbsolutePath());
 5         }
 6         System.out.println("------------------------------------------");
 7         files= FileUtils.listFiles(new File("D:/PCGame"),
 8                 EmptyFileFilter.NOT_EMPTY,DirectoryFileFilter.INSTANCE);//深入阅读子孙级文件
 9         for(File file:files) {
10             System.out.println(file.getAbsolutePath());
11         }
12         System.out.println("------------------------------------------");
13         files= FileUtils.listFiles(new File("D:/PCGame"),
14                 new SuffixFileFilter("txt"),DirectoryFileFilter.INSTANCE);//过滤出指定类型的文件
15         for(File file:files) {
16             System.out.println(file.getAbsolutePath());
17         }
View Code

3.读取文件内容:readFileToString(),readFileToByteArray(),readLines(),lineIterator()方法

 1 //读取文件
 2         String msg = FileUtils.readFileToString(new File("C:\\Users\\Dexin\\Desktop\\java练习\\javaexercise\\chapter10\\print.txt"),"GBK");
 3         System.out.println(msg);
 4         //存于byte数组后再读取
 5         byte[]datas = FileUtils.readFileToByteArray(new File("C:\\Users\\Dexin\\Desktop\\java练习\\javaexercise\\chapter10\\print.txt"));
 6         System.out.println(datas.length);
 7         //逐行读取
 8         List<String>msgs= FileUtils.readLines(new File("C:\\Users\\Dexin\\Desktop\\java练习\\javaexercise\\chapter10\\print.txt"),"GBK");
 9         for(String str:msgs) {
10             System.out.println(str);
11         }
12         //用迭代器逐行读取
13         LineIterator it = FileUtils.lineIterator(new File("C:\\Users\\Dexin\\Desktop\\java练习\\javaexercise\\chapter10\\print.txt"),"GBK");
14         while(it.hasNext()) {
15             System.out.println(it.nextLine());
16         }
View Code

4.写一些内容至指定文件:write(),writeStringToFile(),writeByteArrayToFile(),writeLines()方法

 1 //写出文件
 2     FileUtils.write(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/happy.text"), "今天要努力学习\r\n", "UTF-8");
 3     FileUtils.writeStringToFile(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/happy.text"), "明天要努力学习\r\n", "UTF-8",true);
 4     FileUtils.writeByteArrayToFile(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/happy.text"), "后天要努力学习\r\n".getBytes("UTF-8"),true);
 5     
 6     //写出列表
 7     List<String>list = new ArrayList<String>();
 8     list.add("今天学习IO技术");
 9     list.add("明天学习数据库");
10     list.add("后天写简历");
11     FileUtils.writeLines(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/happy.text"), "UTF-8", list,"--",true);//true表示使用追加写法
View Code

5.复制相关的方法:copyFile(),copyFileToDirectory(),copyDirectoryToDirectory(),copyDirectory(),copyURLToFile(),IOUtils.toString()方法

 1 //复制文件
 2         FileUtils.copyFile(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/bbbb.jpg"), new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/copy of bbbb.jpg"));
 3         //复制文件到目录
 4         FileUtils.copyFileToDirectory(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10/bbbb.jpg"), new File("D:"));
 5         //复制目录到目录里
 6         FileUtils.copyDirectoryToDirectory(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter10"), new File("D:"));
 7         //复制目录本身
 8         FileUtils.copyDirectory(new File("C:/Users/Dexin/Desktop/java练习/javaexercise/chapter04"), new File("D:/copy of chapter04"));
 9         //拷贝URL内容
10         String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1585907808396&di=412204d0ec99ee7749d1ed9a40205cec&imgtype=0&src=http%3A%2F%2Fpic9.iqiyipic.com%2Fimage%2F20200307%2F48%2Fc6%2Fv_145827302_m_601_m1_480_360.jpg";
11         FileUtils.copyURLToFile(new URL(url),new File("d:/xiaohudie.jpg"));
12         //拷贝URL内容方法2
13         String datas = IOUtils.toString(new URL("http://www.163.com"),"GBK");
14         System.out.println(datas);
View Code

 

posted @ 2020-03-29 19:32  菅兮徽音  阅读(294)  评论(0编辑  收藏  举报