zoukankan      html  css  js  c++  java
  • Java I/O流操作(三)File文件操作及打印流和序列流合并流

     
    - -------------------------------------------File文件操作---------------------------------------------
     用来将文件或者文件夹封装成对象
    方便对文件与文件夹进行操作
    File对象可以作为参数传递给流的构造函数.
    下面来看一下File类的构造方法:

    File file =new File("a.txt");

    File file2 =new File("C:\\file\\test\\a.txt");
    File d =new File("C:\\file\\test\\");
    File file3 =new File(d, "a.txt");
    File file4 =new File("C:\\file\\test\\","a.txt");//这和file3是一回事
    System.out.println(file +"\r\n" + file2 + "\r\n" + file3 +"\r\n" + file4 + "\r\n");
    控制台输出为:
    a.txt
    C:\file\test\a.txt
    C:\file\test\a.txt
    C:\file\test\a.txt
    但是我们在程序中,文件的路径分隔符只能在windows平台下,在Linux就不能用了,怎么现在跨平台呢?
    File file5 = new File("C:"+File.separator+"file"+File.separator+"test"+File.separator+"", "a.txt");
     
    接下来就是File类的常用方法了:
    创建方法:
     boolean   createNewFile ()在指定位置创建文件,如果文件不存在,则创建成功返回true,如果文件已经存在,则不创建,返回false
    这和输出流不同,输出流一旦实例化就会创建文件,文件不存在创建,存在则覆盖.
    mkdir ()创建文件夹
    mkdirs ()创建文件夹,包括父文件夹
    删除方法:
    boolean delete()
    void deleteOnExit()
    这两个方法是有区别的:
    delete ()根据抽象的路径名称删除文件,如果程序出现异常没有执行到该行代码,那么这个文件就不会被执行,有人会说放在finally执行,但是如果一个程序正在使用该文件,那么这个文件还是不能被删除.
    deleteOnExit()这个方法不会发生这种情况,因为该方法在虚拟机停终止,文件就会被删除.
    判断方法:
    exists ()  表示抽象的路径名称所指示的文件或文件夹是否存在
    canExecute ()应用程序能否执行抽象路径名称所指示的文件
    canRead ()应用程序能否读取抽象路径名称所指示的文件
    canWrite ()  应用程序能否修改抽象路径名称所指示的文件
    isDirectory ()抽象路径名称所指示的是不是文件夹
    isFile ()抽象路径名称所指示的是不是文件
    isAbsolute ()判断是否是绝对路径
    File file =new File("a.txt");
    System.out.println("isDirectory:"+file.isDirectory());
    System.out.println("isFile:"+file.isFile());
    发现控制台输出

    isDirectory:falseisFile:false

    发现它既不是文件也不是目录,为什么会出现这样的情况呢?
    原来用上面的两个方法判断时候,需要先判断该抽象的路径名称所指定的file和directory是否存在.存在才能进行判断.
     
    获取信息:
     
    File   getAbsoluteFile ()  返回File对象的绝对路径,但是他把这个字符串封装成了File对象返回 这也是和 getAbsolutePath的主要区别
    String   getAbsolutePath ()  返回File对象的绝对路径
    String   getPath ()  返回File对象的路径,如果File里的抽象路径名称是绝对路径,如果是相对路径,就返回相对路径
    String   getName ()如果File对象里的抽象路径名称指定的是目录,那么返回的目录最后的文件夹名称,如果是文件,则返回文件的名称
    String   getParent () 如果File对象里的抽象路径名称指定的是目录,那么返回的目录最后的文件夹的上一个文件夹的名称,如果是文件,则返回文件所在目录的名称,如果象路径名称指定的是相对路径,有可能返回null,如:File file = new File("a.txt");那么该file的父目录就是null.
    File   getParentFile ()这和 getParent的区别就是 ,这个方法把getParent方法的返回值封装成了File对象
    long   length ()  返回文件的大小

    renameTo ( File  dest)  重命名:
    例如:
    File f =new File("C:\\test\\test.txt");
    File f2 =new File("C:\\test\\testDemo.txt");
    f.renameTo(f2);
    如果盘符或者目录不同这就成了剪切了
     
    文件列表:
    File []   listRoots ()  返回系统盘符的名称 如:C D盘等
    String[]   list ()  返回File目录下的所有文件 如果抽象的路径名称指定的是一个文件将会出现空指针异常;并且该目录一定要存在
    例如1:
    for(File file: File.listRoots()){
    System.out.println(file);
    }
    输出结果为:
    C:\
    D:\
    E:\
    F:\
    G:\
    例如2:
    File file =new File("C:\\");
    for (String name : file.list()) {
    System.out.println(name);
    }
    输出结果为:C盘目录下的所有文件和目录包含隐藏文件,但是不包含子文件夹里的文件
     
    文件过滤:
    例如我想输出在某个文件夹下的java文件,那么这时候就要用到过滤文件:
    String[]   list ( FilenameFilter  filter)  我们查看API不难发现, FilenameFilter  是一个接口里面只有一个方法booleanaccept(File dir,String name)

    publicstatic void method_1() {

        final File file =new File("D:\\");
        String[] names = file.list(new FilenameFilter() {
        publicboolean accept(File dir, String name) {
            return name.endsWith(".java");
            }
        });
     
        for (String name : names)
        System.out.println(name);
     

    }

    下面来看一下:
    File[]   listFiles ()  ;这个方法和 list ()  方法的区别是 list ()  方法是返回一个个字符串的,而 listFiles ()是返回一个个File对象.那么就可以通过File对象获取文件的信息了,所以File[]listFiles()方法更使用一些.例如:
    File file =new File("C:\\");
    for(File file2 : file.listFiles()){
    System.out.println(file2.getName());
    }
    listFiles ()同样也有自己的过滤功能.通过 listFiles ( FileFilter  filter)  方法可以实现.

    通过递归实现列出目录下的所有文件
    publicstatic void main(String[] args) {
    File file =new File("E:\\MyeclipseWorkbenck\\shop");
    method_1(file);
    }
     
    publicstatic void method_1(File file) {
    System.out.println(file.getAbsolutePath());
    File[] files = file.listFiles();
    for (File file2 : files) {
    if(file2.isDirectory()){
    method_1(file2);
    }else {
    System.out.println(file2.getName());
    }
     
    }
    }
     
    删除带目录的文件,如果直接使用delete方法,则不能删除成功,因为java删除文件的原理是这样的,把最里面的文件删除,然后删除文件夹
    publicstatic void main(String[] args) {
        File file =new File("D:\\java");
        deleteDir(file);
    }
    publicstatic void deleteDir(File file){
        File[] files = file.listFiles();
        for(File file2 : files){
        //如果是目录
            if(file2.isDirectory()){
        //则使用递归 调用本身
            deleteDir(file2);
        }else {
        //不是目录就直接删除
            file2.delete();
        }
        }
        //然后删除空文件夹
        file.delete();
    }
     
    怎么把java文件的路径存在一个文件里面,方便以后查找.
    publicclass JavaFileItem {
    publicstatic void main(String[] args) {
        List<File> list =new ArrayList<File>();
        saveJavaFilePath(new File("E:\\MyeclipseWorkbenck\\HeimaTest"), list);
        writeFilePath(list,"javaItem.txt");
    }
    //则把java文件放在集合中
    publicstatic void saveJavaFilePath(File dir, List<File> list) {
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                saveJavaFilePath(file, list);
            }else {
        //如果是java文件,则把该文件放在集合中
            if (file.getAbsolutePath().endsWith(".java"))
                list.add(file);
            }
        }
        }
    //把java的路径信息写入文件中
    publicstatic void writeFilePath(List<File> files, String targetFile) {
    BufferedWriter buffw =null;
    try {
            FileWriter fw =new FileWriter(targetFile);
            buffw =new BufferedWriter(fw);
            for (File file : files) {
                //把java文件的绝对路径写入文件
                buffw.write(file.getAbsolutePath());
                //换行
                buffw.newLine();
                //使用字符流注意刷新
                buffw.flush();
            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (buffw !=null)
                    buffw.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    这里就是使用递归和IO操作的结合了.
    -------------------------关于Properties类:--------------------------------------------
     
    关于Properties类:
    Properties是Hashtable的子类,也就是说它具备map结婚的特点,而且它里面存储的键值对都是字符串
    他是集合和IO相结合的集合容器
    该对象的特点是可以用于键值对形式的配置文件
    getProperty ( String  key)  根据key从Properties对象中获取值
    setProperty ( String  key, String  value)  为Properties对象设置key和value
    store ( OutputStream  out, String  comments)  把Properties对象储存到一个文件里面去,底层通过字节输出流处理
    store ( Writer  writer, String  comments)  这是JDK1.6后才有的,直接使用字符输出流就可以把Properties对象储存到文件中
    load ( InputStream  inStream)  读取属性列表从字节输入流中,加载某个键值对文件,使得Properties与该文件相关联
    load ( Reader  reader)  这是JDK1.6后才出现的,读取属性列表从字符输入流中,
    模拟限制软件使用次数:
    publicstatic void count()throws IOException{
        Properties properties =new Properties();
        File file =new File("count.ini");
        if(!file.exists()){
            file.createNewFile();
        }
        InputStream is =new FileInputStream(file);
        properties.load(is);
        String times = properties.getProperty("times");
        int count = 0;
        if(times!=null){
            count = Integer.parseInt(times);
            if(count>=5)
            System.out.println("你使用的次数已到,请续费!");
        }
        count++;
        OutputStream os =new FileOutputStream(file);
        properties.setProperty("times", count+"");
        properties.store(os,"count times");
        os.close();
        is.close();
    }
     
    ----------------------------------打印流------------------------
    下面学习打印流对象PrintStream  PrintWriter
    首先 PrintStream

    大概的意思是说PrintStream相比其他的输出流增强了许多功能,也就是很方便的打印数据,另外PrintStream还可以自动刷新, 也就是说一个字节数组被写入或者调用println方法或者写入了换行字符或者字节\n 后这个flush方法会被自动调用
    PrintStream的常用的构造方法:
    PrintStream ( File  file)
    PrintStream ( OutputStream  out)
    PrintStream ( OutputStream  out, boolean autoFlush)  
    PrintStream ( String  fileName)
    PrintStream ( OutputStream  out, boolean autoFlush,  String  encoding)
    看一下 PrintWriter的API

    大概的意思是说,PrintWriter类不像PrintStream类,如果设置了自动刷新(PrintWriter(Writer out, boolean autoFlush) 或者通过PrintWriter(OutputStream out, boolean autoFlush) 设置),只有当调用println()printf() format()方法才会被刷新,而不是无论什么时候只要出现换行字符就会输出,这些方法使用的是平台自己的行分隔符标准,而不是使用换行字符.
    接着看一下他的主要构造方法:
    PrintWriter ( File  file)
    PrintWriter ( String  fileName)
    PrintWriter ( OutputStream  out)
    PrintWriter ( OutputStream  out, boolean autoFlush)  
    PrintWriter ( Writer  out)
    PrintWriter ( Writer  out, boolean autoFlush)
    比较PrintStream和PrintWriter的构造方法的最大区别PrintWriter可以接受字符输出流Writer而PrintStream不能,所以PrintWriter更常用.
    下面通过一个实例来运用它:
    publicstatic void print()throws IOException{
        //获取键盘输入
        BufferedReader buffr =new BufferedReader(new InputStreamReader(System.in));
        //目的是控制台
        PrintWriter pw =new PrintWriter(System.out);
        String value =null;
        while((value=buffr.readLine())!=null){
            pw.write(value);
            //注意刷新
            pw.flush();
        }
        pw.close();
        buffr.close();
     
    }
    控制太输出如下:

    发现他没有换行,看上去不美观:怎么实现换行呢?我们来看一下这两个个方法
    println ( String  x)
    API是这样解释 println ( String  x)方法的Prints a String and then terminates the line. This method behaves as though it invokes   print(String)  and then println().
    先打印字符串然后终止这行,也就是先调用print(String str)方法然后在调用println()方法.
     
    API是这样解释 println() 方法 的
    Terminates the current line by writing the line separator string. The line separator string is defined by the system property line.separator, and is not necessarily a single newline character ( '\n'). 也就是通过行分隔符终止当前行,行分隔符通过系统属性 line.separator设置的而不需要简单的换行符'\n'
    是不是我们通过println();方法就可以解决上面的问题呢?
    while((value=buffr.readLine())!=null){
        pw.write(value);
        pw.println();//终止一行
        //手动刷新
        pw.flush();
    }
    还有方法可以解决,因为上面说了可以通过设置是否自动刷新而不是手动刷新,所以可以把  pw.flush();注释掉如:
    PrintWriter pw =new PrintWriter(System.out,true);//设置自动刷新
    String value =null;
    while((value=buffr.readLine())!=null){
        pw.write(value);
        pw.println();//因为println()printf()format()都会触发刷新
        //pw.flush();
    }
     
    我们还可以不使用write(),使用println(String)就会更加简单
    PrintWriter pw =new PrintWriter(System.out,true););//设置自动刷新
    String value =null;
    while((value=buffr.readLine())!=null){
        pw.println(value);();//因为println()printf()format()都会触发刷新
    }
     
    我们还可以猜想:
    PrintWriter pw =new PrintWriter(System.out,true););//设置自动刷新
    String value =null;
    while((value=buffr.readLine())!=null){
    pw.write(value+"\r\n");//末尾加上换行符是否会触发自动刷新呢?
    }
    答案是否定的, 在PrintWriter的API有这样一句话These methods use the platform's own notion of line separator rather than the newline character. 也就是说
    是否会触发自动刷新,java内部不是使用换行符("\r\n")而是使用平台内部的行分隔符(当然在windows他们是一样的).
    那么我们可不可以模拟这个java内部所谓的行分隔符呢?在学习System类的时候我们可以得到系统的环境变量,在里面我们发现了行分隔符 "line.separator"
     
    我们来测试一下
    PrintWriter pw =new PrintWriter(System.out,true););//设置自动刷新
    while((value=buffr.readLine())!=null){
    pw.write(value+System.getProperty("line.separator"));//我们使用writer方法,里面的字符串参数加上行分隔符,因为java api里面说println()因为内部加上了行分隔符才会触发刷新的,那么现在我们手工加上行分隔符会触发刷新吗?
    }
    测试的结果还是不行!
    那么为什么?java不是要系统的行分隔符吗?我现在已经加上了行分隔符还不行呢?
    我们来看一下PrintWriter的源代码是怎么定义println(String)方法的
    println(String)的定义:
        publicvoid println(String x) {
            synchronized (lock) {
                print(x);//先打印数据
                println();//再打印行分隔符,我们在进入println()是怎么定义的,
            }
        }
     
    println()的定义:
        publicvoid println() {
            newLine();//打开是怎么样定义的
        }
    newLine()方法的定义:
    privatevoid newLine() {
        try {
            synchronized (lock) {
            ensureOpen();
            out.write(lineSeparator);//写入行分隔符
            if (autoFlush)//判断是否设置刷新
                out.flush();//如果设置为true,那么调用flush()方法
            }
        } catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        } catch (IOException x) {
            trouble =true;
        }
    }
    经过我查看writer()方法的源代码,没有发现他去判断是否刷新,
    结论:尽管我们在使用writer(String)方法的String参数后面加上了行分隔符,但是在writer方法里面根本不去判断是否设置了autoFlush=true
    所以我们在writer(String)方法的String参数后面加上了行分隔符也不能达到预期的效果!
    如果我们想更加了解PrintStream和PrintWriter的区别,查看源代码是最好的帮手.PrintStream是字节输出流的子类,PrintWriter是字符输出流的子类.
     
     
    ----------------------------------------- 序列流-合并流---------------------------------------------------------------------
    简单的说就是把多个字节输入流合并成一个字节输入流,
    SequenceInputStream ( Enumeration <? extends  InputStream > e)  里面传一个 Enumeration里面的元素使用了泛型限定.
    SequenceInputStream ( InputStream  s1, InputStream  s2)  里面传入两个字节输入流对象
    实例:怎么把3个文件的内容输入到一个文件中:
    //通过Vector可以获取Enumeration
    Vector<InputStream> vector =new Vector<InputStream>();
    vector.add(new FileInputStream("C:\\1.txt"));
    vector.add(new FileInputStream("C:\\2.txt"));
    vector.add(new FileInputStream("C:\\3.txt"));
    //实例化合并流
    SequenceInputStream sequence =new SequenceInputStream(vector.elements());
    InputStreamReader isr =new InputStreamReader(sequence);
    BufferedReader fr=new BufferedReader(isr);
    BufferedWriter bw =new BufferedWriter(new FileWriter("C:\\123.txt"));
    String value =null;
    while((value=fr.readLine())!=null){
    bw.write(value);
    bw.newLine();
    }
    bw.close();
    sequence.close();
     
    -----------------------------------------切割流------------------------------------------------
    需求  :一个MP3文件切割成几个文件:
     
    publicstatic void cut()throws Exception {
        InputStream is =new FileInputStream("C:\\mp3\\卓依婷- 好人好梦.mp3");
        OutputStream os =null;
        byte[] buffer =new byte[1024*1024];
        int len=0;
        int name = 1;
        while ((len=is.read(buffer))!=-1) {
            //每一次循环都会生成一个文件,这样就实现了切割
            os =new FileOutputStream("C:\\mp3\\part\\"+(name++)+".part");
            //每个文件写1M,最后一个文件可能没有1M
            os.write(buffer,0,len);
            os.close();
        }
        is.close();
    }
    发现part目录多了4个文件,并且大小和以前的文件一样:

    从而也验证了前面4个文件都是1M最后一个没有1M的结论
    现在怎么把上面的4个文件重新合并成一个文件
    publicstatic void merger()throws Exception {
        List<InputStream> list =new ArrayList<InputStream>();
        for (int i = 1; i <= 4; i++) {
            list.add(new FileInputStream("C:\\mp3\\part\\" + (i) +".part"));
        }
        final Iterator<InputStream> iterator = list.iterator();
        Enumeration<InputStream> enumeration =new Enumeration<InputStream>(){
        publicboolean hasMoreElements() {
        return iterator.hasNext();
        }
        public InputStream nextElement() {
        return iterator.next();
    }
    };
        SequenceInputStream sequence =new SequenceInputStream(enumeration);
        OutputStream os =new FileOutputStream("C:\\mp3\\part\\卓依婷- 好人好梦.mp3");
        byte[] buffer =new byte[1024];
        int len = 0;
        while((len=sequence.read(buffer))!=-1){
            os.write(buffer,0,len);
        }
        os.close();
        sequence.close();
    }

    转载请注明出处 : http://blog.csdn.net/johnny901114/article/details/8710433

  • 相关阅读:
    JMeter性能测试中控制业务比例
    软件版本命名规范
    软件测试方法——静态测试与动态测试
    安装BugFree 3.0.4时出现的问题
    Linux下给mysql创建用户分配权限
    LoadRunner 测试脚本
    linux dd命令详解
    Linux查看CPU和内存使用情况
    Error:java: 无效的源发行版: 10
    rf接口自动化之结果校验
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/2979606.html
Copyright © 2011-2022 走看看