文件与IO(java)

文件与IO

1、file类

  • 基本概念

    • file类:表示文件和目录路径名的抽象表示;
    • file类可以实现文件的创建、删除‘、重命名、得到路径、创建时间等等,是唯一与文件本身有关的操作类;
  • file类的操作方法

    • 表示路径分隔符: public static final String separator

    • 构造file类实例,要传入路径 : public File(String pathname)

    • 创建新文件 :public boolean creatNewFile()

    • 删除文件 :public boolean delete()

    • 判断给定的路径是否是文件夹/文件 : public boolean isDirectory() / isFile()

    • 列出文件夹中的文件:public String[] list[]

    • 列出文件夹中的所有文件,以file对象返回 :public File[] listFiles[]

    • 创建新的文件夹 : public boolean mkdir()

    • 返回文件大小 : public long length()

    • 为文件重命名 :public boolean renameTo(File dest)

    • 路径名字符串 : public getPath()

    • 案例演示

      public class FileDemo {
          public static void main(String[] args) {
              File fi = new File("e:"+File.pathSeparator+"java"+File.pathSeparator+"Test_case"+File.pathSeparator+"fistIOFile");
              if(!fi.exists()){
                  try {
                      fi.createNewFile();//创建文件
                      System.out.println("文件创建成功");
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
              System.out.println("fi是否是文件呢?:"+fi.isDirectory());
      
              File f2 =new File("e:\\java\\Test_case\\testio");
              boolean del = f2.delete();
              System.out.println("文件是否删除?:"+del);//删除文件夹需要清除里面内容
              String[] filenames = f2.list();
              //打印文件夹下的所有文件名
              System.out.println(Arrays.toString(filenames));
      
              //列出当前目录下的所有文件,以file对象返回
              File[] fs = f2.listFiles();
              System.out.println(Arrays.toString(fs));
              for (File f:fs){
                  System.out.println("length="+f.length());
                  System.out.println("name="+f.getName());
                  System.out.println("相对路径="+f.getPath());
                  System.out.println("绝对路径="+f.getAbsolutePath());
                  Date date =new Date(f.lastModified());
                  DateFormat df =new SimpleDateFormat("HH:mm:ss");
                  System.out.println("文件最后修改的时间"+df.format(date));
              }
              //创建一个文件夹
              File f3 =new File("e:\\java\\Test_case\\testio\\newdectory");
              f3.mkdir();
              //给文件夹改名
              f3.renameTo(new File("e:\\java\\Test_case\\testio\\alchange"));
              System.out.println(f3.getName());
          }
      }
      

2、字节流

  • IO流

    • IO流:输入输出流(Input/Output)
    • 流失一组有顺序的,有起始和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流
  • IO流的分类

    • 根据处理数据类型的不同分为:字符流和字节流
    • 根据数据流向不同分为:输入流和输出流
  • 字节输出流

    • OutputStream类定义 public abstract class OutputStream extends Object implements Closeable,Flushable
    • 此类抽象类是表示输出字节流的所有类的超类。输出流接收输出字节并将这些字节发送到inputStream类某接收器
    • 要向文件中输出,使用FileOutPutStream类
    //输出流
    public static void main(String[] args) {
            out();
            in();
        }
        //输出流
        private static void out(){
            //确定目标文件
            File file =new File("E:\\java\\简单案例\\123.txt");
            //构建一个输出流对象
            try{
                OutputStream out = new FileOutputStream(file,true);//append=ture表示追加内容,不覆盖
                //写入输出内容
                String info = "我在你家学java\r\n";//“\r\n”表示换行
                out.write(info.getBytes());
                //关闭流
                out.close();
                System.out.println("输出完成!!");
            }
            catch (FileNotFoundException e){
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
  • 字节输入流

    • 定义: public abstract class InputStream extends Object impements Closeable
    • 此抽象类是表示字节输入流的所有类的超类
    • FileInputStream 从文件系统中的某个文件中获得输入字节
    //输入流
        private static void in(){
            File file = new File("E:\\java\\简单案例\\123.txt");
            //构建一个输入流对象
            try {
                InputStream in = new FileInputStream(file);
                //定义一个1M字节的数组
                byte[] bytes = new byte[1024*10];
                StringBuilder buffer = new StringBuilder();
                int len = 1;//每次读取的字节长度
                //把数据读入数组中返回字节数,当不等于-1时,表示读取数据,等于-1表示读完
                while((len=in.read(bytes))!=-1){
                    //将读到的字节数组,再转换成字符串内容,添加到StringBuilder中
                    buffer.append(new String(bytes,0,len));
                }
                System.out.println(buffer);
                in.close();
                System.out.println("写入成功!!!");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 输入输出字节流的操作原理,每次只会操作一个字节,(从文件中读取或者写入)

​ 字节操作流:默认每次执行写入操作会直接把数据写入1文件

3、字符流

  • Writer

    • 写入字符流的抽象类。子类必须实现的方法有write(char[],int,int)、flush() 和 close();但是,多数子类将重写此处定义的一些方法,以提供更高效率或其他功能。
    • 与OutputStream一样,对文件的操作使用,用FileWrite类文成。
  • Reader

    • 用于读取字符流的抽象类,子类必须实现的方法只有read(char[],int,int) 和 close();但是 多数子类将重写此处定义的一些方法,以提供更高效率或其他功能。
    • 使用FileReader类进行实例化操作。
  • 注意

    • 每次操作的单位是一个字符;
    • 文件字符操作流会自带缓存,默认大小为1024k,在缓存满后,或手动刷新缓存,或关闭流时会把数据写入文件;
  • 字节流与字符流之间的选择

    • 一般操作非文本文件时,使用字节流,操作文本文件时,建议使用字符流;
//字符流
System.out.println(cs);
public class CharStreamDemo {
    public static void main(String[] args) {
        out();
        in();
    }
    //输出
    private static void out(){
        File file =new File("E:\\java\\简单案例\\123.txt");
        try {
            Writer out = new FileWriter(file,true);
            out.write("你在大厂还好吗?\r\n");
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //输入
    private static void in(){
        File file =new File("E:\\java\\简单案例\\123.txt");
        try {
            Reader in = new FileReader(file);
            char[] cs = new char[1];
            int len = -1;
            StringBuilder buffer = new StringBuilder();
            while ((len=in.read(cs))!=-1){
                buffer.append(cs,0,len);
            }
            in.close();
            System.out.println(buffer);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4、字节字符的转换流

转换流,可以将一个字节流转换为字符流,也可以将一个字符流转换成字节流;

  • OutputStreamWriter: 可以将输出的字符流转换成字节流的输出形式
  • InputStreamReader :将输入的字节流转换为字符流的字符流输入形式
public class ChangeStreamDemo {
    public static void main(String[] args) throws FileNotFoundException {

            InputStream in = new FileInputStream("E:\\java\\简单案例\\123.txt");
            OutputStream out = new FileOutputStream("E:\\java\\简单案例\\123.txt",true);
            Writer(out);
            read(in);
        }

    private static void read(InputStream in){
        Reader reader =new InputStreamReader(in, Charset.defaultCharset());
        char[] cs = new char[1024];
        int len = -1;
        try {
            while ((len=reader.read(cs))!=-1);
            {
                System.out.println(new String(cs));
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static void Writer(OutputStream out){
        try {
            Writer writer = new OutputStreamWriter(out,Charset.defaultCharset());
            writer.write("不好的话换我上奥!!!");
            writer.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

5、缓冲流

使用缓冲流的好处:能够更高效的读写信息,原理四将数据先缓冲起来,然后一起写入或者读取出来。 实现更高效的读取和写入操作;

​ 解决在写入文件操作时,频繁的操作文件所带来的性能降低;

  • 字节缓冲流

    • BufferedInputStream : 为另一个输入流添加一些功能,在创建BufferedInputStream时,会创建一个内部缓冲区数组,用于缓冲数据;
    • BufferedOutputStream : 通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

public class BufferStreamDemo {
public static void main(String[] args) {
// Write();
Read();
}
private static void Write(){
try {
OutputStream out = new FileOutputStream(“E:\java\简单案例\123.txt”,true);
BufferedOutputStream aos = new BufferedOutputStream(out);
String info = “我在家里学java”;
aos.write(info.getBytes());
aos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void Read(){
try {
InputStream in = new FileInputStream(“E:\java\简单案例\123.txt”);
BufferedInputStream bas = new BufferedInputStream(in);
byte[] bytes = new byte[1024];
int len = -1 ;
while ((len=bas.read(bytes))!=-1);{
System.out.println(new String(bytes));
}
bas.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}




* 字符缓冲流

* BufferedReader : 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

```java
   private static void Read(){
        try {
            InputStream in =  new FileInputStream("E:\\java\\简单案例\\123.txt");
            //为字符流提供缓冲,已达到高速读取的目的
            BufferedInputStream bas = new BufferedInputStream(in);
            byte[] bytes = new byte[1024];
            int len;
            while ((len=bas.read(bytes))!=-1);{
                System.out.println(new String(bytes));
            }
            bas.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • BufferedWriter : 将文本写入字符流输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
private static void CharWriter(){
        File file = new File("E:\\java\\简单案例\\123.txt");
        try {
            Writer writer = new FileWriter(file);
            //为字符流提供缓存,提高写入速率
            BufferedWriter bw =new BufferedWriter(writer);
            bw.write("你在监狱还好吗?");
            bw.flush();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

6、打印流

打印流的主要功能就是用于输出,可以很方便地进行输出,在整个IO包中打印流分为两种类型:

​ 字节打印流:PrintStream (增加输出功能)

private static void BytePrint(){
        File file = new File("E:\\java\\简单案例\\123.txt");
        try {
            OutputStream out = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(out);
            //打印流,增加输出的便利性
            PrintStream ps = new PrintStream(bos);
            ps.println("干你娘地别说话!!");
            ps.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

​ 字符打印流:PrintWriter ()

private static void CharPrint(){
        File file = new File("E:\\java\\简单案例\\123.txt");
        try {
            Writer out = new FileWriter(file,true);
            BufferedWriter bos = new BufferedWriter(out);
            //打印流,增加输出的便利性
            PrintWriter ps = new PrintWriter(bos);
            ps.println("嘴长我身上我tm就得说!!");
            ps.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

7、对象流和序列化

对象流的两个类:
  • ObjectOutputStream 将java对象的基本数据类型与图像写入OutputStream ;

  • ObjectInputStream 对以前使用ObjectOutputStream写入的基本类型数据和对象进行反序列化;

  • //如果一个类创建的对象,需要被序列化,该类必须实现一个Serializable接口
    //Serializable 是一个标记接口,没有任何定义,为了告诉jvm该类可被序列化
    
    //什么时候对象需要被序列化呢?
    //1、把文件保存到文件中(存储在物理介质中)
    //2、对象需要在网络上传输
    
序列化一组对象:
  • 在序列化操作中,同时序列化多个对象时,反序列化也必须按顺序操作;
  • 序列化一组对象可采用,对象数组的形式,因为对象数组可以向Object进行转型操作;
transient关键字:

​ 如果用transient声明一个实例变量,当对象存储时,它的值不需要维持(在序列化中被忽略的);

8、字节数组流(基于内存操作)

  • ByteArrayinputStream

    包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read方法要提供的下一个字节。关闭ByteArrayinputStream 无效。此类中的方法在关闭此流后仍可调用,而不会产生任何IOException;

  • ByteArrayOutputStream

    此类实现了一个输出流,其中的数据被写入一个byte数组。缓冲区会随着数据的不断写入而自动增长;可使用 toString ()获得数据;关闭ByteArrayOutputStream 无效;此类中的方法在关闭此流后仍可调用,而不会产生任何IOException;

public class ByteArrayStreamDemo {
    public static void main(String[] args) {
        byteArray();
    }
    private static void byteArray(){
        String s = "i03232230lo02vle2334Y20O34324U";
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int curr=-1;   //每次读取的字节
        while((curr=bais.read())!=-1){
            if(curr>=65&&curr<=90 || curr>=97&&curr<=122){
                baos.write(curr);
            }
        }
        System.out.println(baos.toString());

    }
}

9、数据流

  • DataInputStream :数据输入流允许程序以与机器无关方式从底层输入流中读取基本java数据类型;应用程序可以使用数据输出流写入稍后由数据输入流读取的数据;DataInputStream对于多线程访问不一定是安全的。线程安全是可选的,它由此类方法的使用者负责。
   private static void write(){
        File file = new File("E:\\java\\简单案例\\test.bat");
        try {
            OutputStream out = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(out);
            DataOutputStream dos = new DataOutputStream(bos);
            dos.writeInt(10);//写入四个字节
            dos.writeByte(1);//写入一个字节
            dos.writeUTF("爱你");
            dos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • DataOutputStream:数据输出流允许应用程序以适当方式将基本java数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
private static void read(){
        File file = new File("E:\\java\\简单案例\\test.bat");
        try {
            InputStream in = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(in);
            DataInputStream dis = new DataInputStream(bis);
            int sum = dis.readInt();
            byte b = dis.readByte();
            String s = dis.readUTF();
            System.out.println(sum+","+b+","+s);
            dis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 案例:文件分割与合并

    • 模拟压缩软件分割文件功能
    public class FileDivisionMergeDemo {
        private static void Division(File targetFile, long cutSize){
            if(targetFile==null)
                return;
            int num = targetFile.length() % cutSize == 0 ?
                    (int)(targetFile.length() / cutSize) :
                    (int)(targetFile.length() / cutSize +1);
            try {
                //构建一个文件输入流
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(targetFile));
                BufferedOutputStream bos = null;
    
                byte[] bytes = null;    //每次读取的字节数
                int len = -1;
                int count = 0;
    
                //循环次数等于生成文件数量
                for (int i = 0; i < num; i++) {
                    bos = new BufferedOutputStream(new FileOutputStream(
                            new File("E:\\java\\相关书籍\\division\\"+"temp_"+(i+1)+"_"+targetFile.getName())));
                    if(cutSize <= 1024){
                        bytes = new byte[(int)cutSize];
                        count = 1;
                    }else {
                        bytes = new byte[1024];
                        count = (int)cutSize / 1024;
                    }
                    while (count>0 && (len = bis.read(bytes))!=-1){
                        bos.write(bytes,0,len);
                        bos.flush();
                        count--;
                    }
                    //计算余数
                    if(cutSize % 1024 !=0){
                        bytes = new byte[(int)cutSize % 1024];
                        len = bis.read(bytes);
                        bos.write(bytes,0,len);
                        bos.flush();
                        bos.close();
                    }
                }
                bis.close();
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            File file = new File("E:\\java\\相关书籍\\Java编程思想.zip");
            Division(file,1024*1024);
        }
    }
    

10、合并流、字符串流、管道流

  • 合并流
    • SequenceInputStream :表示其他输入流的逻辑串联;它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,知道到达包含的最后一个输入流的文件末尾为止。

      public class FileDivisionMergeDemo {
          private  static  void  Merge(Enumeration<InputStream> em){
              //构造一个合并流
              SequenceInputStream sis = new SequenceInputStream(em);
              try {
                  BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream("E:\\java\\相关书籍\\division\\Merge_Java编程思想第五版.mobi"));
      
                  byte[] bytes = new byte[1024];
                  int len = -1;
                  while ((len=sis.read(bytes))!=-1){
                      bos.write(bytes,0,len);
                      bos.flush();
                  }
                  bos.close();
                  sis.close();
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      //    private static void Division(File targetFile, long cutSize){
      //        if(targetFile==null)
      //            return;
      //        int num = targetFile.length() % cutSize == 0 ?
      //                (int)(targetFile.length() / cutSize) :
      //                (int)(targetFile.length() / cutSize +1);
      //        try {
      //            //构建一个文件输入流
      //            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(targetFile));
      //            BufferedOutputStream bos = null;
      //
      //            byte[] bytes = null;    //每次读取的字节数
      //            int len = -1;
      //            int count = 0;
      //
      //            //循环次数等于生成文件数量
      //            for (int i = 0; i < num; i++) {
      //                bos = new BufferedOutputStream(new FileOutputStream(
      //                        new File("E:\\java\\相关书籍\\division\\"+"temp_"+(i+1)+"_"+targetFile.getName())));
      //                if(cutSize <= 1024){
      //                    bytes = new byte[(int)cutSize];
      //                    count = 1;
      //                }else {
      //                    bytes = new byte[1024];
      //                    count = (int)cutSize / 1024;
      //                }
      //                while (count>0 && (len = bis.read(bytes))!=-1){
      //                    bos.write(bytes,0,len);
      //                    bos.flush();
      //                    count--;
      //                }
      //                //计算余数
      //                if(cutSize % 1024 !=0){
      //                    bytes = new byte[(int)cutSize % 1024];
      //                    len = bis.read(bytes);
      //                    bos.write(bytes,0,len);
      //                    bos.flush();
      //                    bos.close();
      //                }
      //            }
      //            bis.close();
      //
      //        } catch (FileNotFoundException e) {
      //            e.printStackTrace();
      //        } catch (IOException e) {
      //            e.printStackTrace();
      //        }
      //    }
      
          public static void main(String[] args) {
      //        File file = new File("E:\\java\\相关书籍\\Java编程思想.zip");
      //        Division(file,1024*1024);
              try {
                  InputStream in1 =new FileInputStream(new File("E:\\java\\相关书籍\\division\\temp_1_Java编程思想第五版.mobi"));
                  InputStream in2 =new FileInputStream(new File("E:\\java\\相关书籍\\division\\temp_2_Java编程思想第五版.mobi"));
      			//集合工具类,内部使用了数组
                  Vector<InputStream> v = new Vector<InputStream>();
                  v.add(in1);
                  v.add(in2);
      
                  Enumeration<InputStream> em = v.elements();
      
                  Merge(em);
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              }
          }
      }
      
  • 字符串流
    • StringReader :其源为一个字符串的字符流
    public static void main(String[] args) {
            StringReader();
        }
        //以一个字符串为数据流,来构造一个字符流
        private static void StringReader(){
            String info = "you are my favorite fruit";
            StringReader sr = new StringReader(info);
            //流标记器
            StreamTokenizer st = new StreamTokenizer(sr);
    
            int count = 0;
            while (st.ttype != StreamTokenizer.TT_EOF){
                try {
                    if(st.nextToken()==StreamTokenizer.TT_WORD){
                        count++;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            sr.close();
            System.out.println("count="+count);
        }
    
    • StringWriter :一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串;关闭StringWriter无效,此类中的方法在关闭该流后仍可被调用,而不会产生任何IOException;
  • 管道流
    • 管道输入流应该连接到管道输出流,管道输入流提供要写入管道输出流的所有数据。通常,数据由某个线程从PipedInputStream 对象读取,并由其他线程将其写入到相应PipedOutputStream中;不建议对这两个对象尝试使用单线程,因为这样可能死锁线程;管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。

11、Properties文件操作

Properties(java.util.Propertoes):主要用于读取java配置文件,配置文件中很多变量是经常改变的,这样做也是为了方便用户,让用户能够脱离程序本身去修改相关的变量设置;

它提供了几个主要的方法:

  • getProperty(String key)

    用指定的键在此属性列表中搜索属性,也就是通过参数key,得到key所对应的value;

  • load(InputStream inStream)

    从输入流中读取属性列表(键和元素对);通过对指定的文件(比如下面的“config.properties”文件)进行装载来获取该文件中的所有键值对;以供getProperty搜索;

//读操作
public class PropertiesDemo {
    private static  String version="";
    private static  String username="";
    private static  String password="";
    public static void main(String[] args) {
        readProperties();
        System.out.println(version);
        System.out.println(username);
        System.out.println(password);
    }
    private static void readProperties(){
        Properties pt = new Properties();
        try {
            InputStream in = new FileInputStream("E:\\java\\ThreadTest\\src\\com\\test\\iodemo\\config.properties");
            //将数据存到properties中
            pt.load(in);
            //从properties中获取数据
            version=pt.getProperty("app.version");
            username=pt.getProperty("username");
            password=pt.getProperty("password");
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • setProperty(String key,String value)

    调用Hashtable的方法put,通过调用基类的put方法来设置键值对;

  • store(OutputStream out, String comment)

    以适合使用load方法加载到Peoperties表中的格式,将此Properties表中的属性(键和元素对)写入输出流;与load方法相反,该方法将键值对写入到指定文件中去;

//写操作
private static void writeProperties(String version,String username,String password){
        Properties pt = new Properties();
        pt.put("app.version",version);
        pt.put("username",username);
        pt.put("password",password);
        try {
            OutputStream out = new FileOutputStream("config.properties");
            //写文件
            pt.store(out,"update");
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
  • clear()

    清除所有装载的键值对,该方法在基类中;

12、 文件压缩与解压缩

java中实现zip的压缩与解压缩

  • ZipOutputStream

    实现文件的压缩;

  • ZipOutputStream(OutputStream out)

    创建新的zip输出流;

  • void putNextEntry(ZipEntry e)

    开始写入新的Zip文件条目并将流定位到条目数据的开始处;

  • ZipEntry( String name)

    使用指定名称 创建新的ZIP条目;

//压缩文件
public class CompressionAndDeDemo {
    public static void main(String[] args) {
        compression("E:\\过去杂事文档\\学生科.zip",new File("E:\\学生科"));
    }
    private static void compression(String zipFileName, File targetFile){
        System.out.println("压缩中");
        try {
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
            BufferedOutputStream bos = new BufferedOutputStream(out);
            Zip(out,targetFile,targetFile.getName(),bos);
            bos.close();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("压缩成功!!!");
    }
    private static void Zip(ZipOutputStream zOut,File targetFile,
                            String name,BufferedOutputStream bos) throws IOException {
        //如果是个目录
        if(targetFile.isDirectory()){
            File[] files = targetFile.listFiles();
            //如果是空目录
            if(files.length==0){
                zOut.putNextEntry(new ZipEntry(name+"/"));
            }
            for(File f:files){
                //递归 处理
                Zip(zOut,f,name+"/"+f.getName(),bos);
            }
        }
        else {
            zOut.putNextEntry(new ZipEntry(name));
            InputStream in = new FileInputStream(targetFile);
            BufferedInputStream bis = new BufferedInputStream(in);
            byte[] bytes =new byte[1024];
            int len =-1;
            while ((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
            bis.close();
        }
    }
}
  • ZipInputStream

    实现文件的解压

  • ZipInputStream(InputStream out)

    创建新的ZIP输入流

  • ZipEntry putNextEntry()

    读取下一个zip文件条目并将流定位到该条目数据的开始处

//解压文件
private static void decompression(String targetFileName, String parent){
        try {
            //构建解压输入流
            ZipInputStream zIn =new ZipInputStream(new FileInputStream(targetFileName));
            ZipEntry entry = null;
            File file = null;
            while((entry=zIn.getNextEntry())!=null && !entry.isDirectory()){
                file = new File(parent,entry.getName());
                if(!file.exists()){
                    new File(file.getParent()).mkdir();//创建此文件的上级文件
                }
                OutputStream out = new FileOutputStream(file);
                BufferedOutputStream bos = new BufferedOutputStream(out);
                byte[] bytes = new byte[1024];
                int len =-1;
                while((len=zIn.read(bytes))!=-1){
                    bos.write(bytes,0,len);
                }
                bos.close();
                System.out.println(file.getAbsolutePath()+"解压成功!!");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

13、IO常用类体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QDdSmHoX-1625389322029)(C:\Users\17700\AppData\Roaming\Typora\typora-user-images\image-20210704125153807.png)]

14、装饰者设计模式

  • 意图

    动态地给一个对象添加一些额外的职责,就增加功能来说,Decorator模式相比生成子类更为灵活,该模式以对客户端透明的方式扩展对象的功能;

  • 使用环境
    • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加指责;
    • 处理那些可以撤销的职责;
    • 当不能采用生成子类的方法进行扩充时,一种情况是:可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
  • Component(被装饰对象基类)

    定义对象的接口,可以给这些对象动态增加职责;

  • ConcreteComponent(具体被装饰对象)

    定义具体的对象,Decorator可以给它增加额外的职责;

  • Decorator(装饰者抽象类)

    维护指向Component实例的应用,定义与Component一致的接口;

  • ConcreteDecorator(具体装饰者)

    具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责;

15、常见的字符编码

在计算机世界中,任何文字都是以编码形式存在的;

常见的编码有:
  • iso8859-1:

    编码属于单字节编码,最多只能表示0-255的字符范围,主要在英文上应用;

  • GBK/GB2312:

    中文的国际编码,专门用来表示汉字,是双字节编码;

  • unicode

    java中使用此编码方式,也是最标准的一种编码,是使用十六进制表示的编码;但此编码不兼容iso8859-1编码;

  • UTF

    由于unicode不支持iso8859-1编码,而且容易占用更多空间,而且对于英文字母也需要使用两个字节编码,这样使用unicode不便于传输和储存,每个字符的长度从1-6个字节不等,一般在中文网页中使用此编码,因此这样可以节省空间。

造成乱码的根本原因
  • 程序使用的编码与本机编码不统一;
  • 在网络中,客户端与服务端不统一;

16、New IO

**目的:**让java程序员可以实现I/O而无需编写自定义的本机代码;NIO将最耗时的I/O操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度;

流与块的比较
  • 原来的I/O库(在java.io.*中)与NIO最重要的区别是数据打包和传输的方式,原来的I/O以流的方式处理数据,二NIO以块方式处理数据;

  • 面向流的I/O系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O通常比较慢;

  • 一个面向块的I/O系统以块的形式处理数据,每一个操作都在一步中产生或者消费一个数据块,按块处理数据比按流处理要快得多,但是面向块的I/O缺少一些面向流的I/O所具有的优雅性和简单性

缓冲区
  • 在NIO库中,所有数据都是用缓冲区处理的,在读取数据时,直接读到缓冲区中;在写入数据时,它是写入缓冲区中的,任何时候访问NIO中的数据,都是将它放到缓冲区中;

  • 缓冲区其实是一个数组,通常是一个字节数组,但是也可以使用其他种类的数据;一个缓冲区也并是一个数组,缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读写、进程。

缓冲区类型

最常用的缓冲区类型是ByteBuffer,一个ByteBuffer可以在其底层字节数组上进行get/set操作(即字节的获取和设置);

对应每一种java类型都有一种缓冲区:

ByteBuffer

CharBuffer

ShortBuffer

IntBuffer

LongBuffer

FloatBuffer

DoubleBuffer

通道:Channel
  • Channel 是一个对象,可以通过它读取和写入数据;拿NIO与原来的I/O做个比较,通道就像是流;

  • 你不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节;

public static void main(String[] args) throws IOException {
        copyFile();
    }
    //文件通道方式实现复制文件
    private static void copyFile() throws IOException {
        //创建一个输入文件的通道
        FileChannel fcIn = new FileInputStream("E:\\美食网\\法国.jpg").getChannel();
        //创建一个输出文件的通道
        FileChannel fcOut = new FileOutputStream("E:\\美食网\\法国1.jpg").getChannel();

        ByteBuffer buf = ByteBuffer.allocate(1024);
        while((fcIn.read(buf))!=-1){
            buf.flip();
            fcOut.write(buf);
            buf.clear();
        }
        fcIn.close();
        fcOut.close();
        System.out.println("copy successful!!");
    }
Path接口
  • Path表示的是一个目录名序列,其后还可以跟一个文件名,路径中第一个部件是根部件时就是绝对路径,例如:、或者C:\,而允许访问的根部件取决于文件系统;
  • 以根部件开始的路径是绝对路径,否则就是相对路径;
  • 静态的Paths.get方法接受一个或多个字符串,字符串之间自动使用默认文件系统的路径分隔符连接其拉力(Unix是/,Window是),这就解决了跨平台的问题,接着解析连接起来的结果,如果不是合法路径就抛出InvalidPathException异常,否则就返回一个Path对象;
File工具类
  • 读写文件
static path write(path path,byte[] bytes,OpenOption...options) //写入文件

static byte[] readAllBytes(Path path)							//读取文件中的所有字节
  • 复制、剪切、删除
static path copy(Path source, Path target,CopyOption...options)

static path move(Path source, Path target,CopyOption...options)

static void delete(Path path)
static boolean deleteIfExists(Path path)
//案例
public static void main(String[] args) throws IOException {
        File file = new File("E:\\美食网\\法国.jpg");

        Path p1 = Paths.get("E:\\美食网","法国.jpg");
        System.out.println(p1);

        Path p2 = file.toPath();
        System.out.println(p2);

        Path p3 = FileSystems.getDefault().getPath("E:\\美食网\\法国.jpg");

        //File工具类
        Path p4 = Paths.get("E:\\美食网","法国.txt");
        String info ="上厕所记得关门啊!!!";

        try {
            //写操作
            Files.write(p4,info.getBytes("UTF-8"),StandardOpenOption.APPEND);

            //读取操作
            byte[] bytes = Files.readAllBytes(p4);
            System.out.println(new String(bytes));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //复制文件(存在即替换)
        Files.copy(p3,Paths.get("E:\\美食网\\中国美食\\法国.jpg"),StandardCopyOption.REPLACE_EXISTING);
        //移动文件
        Files.move(p3,Paths.get("E:\\美食网\\中国美食\\法国.jpg"),StandardCopyOption.REPLACE_EXISTING);
        //删除文件
        Files.delete(Paths.get("E:\\美食网\\中国美食\\法国.jpg"));
    }
  • 创建文件和目录
 Files.createDirectory(Paths.get("E:\\美食网\\中国美食\\荞凉粉"));
        //创建文件
        Files.createFile(Paths.get("E:\\美食网\\中国美食\\荞凉粉\\荞凉粉.jpg"));
        //添加前、后缀创建临时文件或临时目录
        Path newPath = Files.createTempFile(dir, prefix, suffix);
        Path newPath = Files.createTempDirectory(dir, prefix);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值