14Java的IO流

Posted 素然止步

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了14Java的IO流相关的知识,希望对你有一定的参考价值。

File类

File类常用方法

 例子

import java.io.File;
import java.io.IOException;

/**
 * 
 * @author leak File类只能操作文件本身,但是不能操作文件内容 例如:你可以把一个txt文档增删改查,但是不能对txt里面的内容增删改查
 */
public class Test {
    public static void main(String[] args) {
    // 1访问文件名
        // 这个时候对象f就是abc.txt文件
        // 文件路径的反斜杆\\和斜杆/,如果是\\那么需要\\\\两个,一个做转义符作用D:\\\\abc
        // 如果是斜杆D:/ABC/ABC.TXT,一个就够了
        // File f = new File("文件路径");把文件转为对象操作
        File f = new File("D:/abc/abc.txt");
        // 创建文件对象有两种方式,一种上面的直接加路径
        // 一种就是File f1 = new File("父路径","子路径");
//        File f1 = new File("D:/abc","abc.txt");

        // 使用相对路径来创建file对象
        File f5 = new File("/Test1/src/org/chen/day12/Test.java");
        // 获取当前的文件名,如果是路径,那么就是获取最后一级目录名
        System.out.println(f.getName());
        // 如果new File对象的路径是相对路径,那么getPath就是获取相对路径地址
        // 如果是绝对路径,那么getPath就是获取绝对的地址
        System.out.println(f.getPath());
        // 获取当前文件/夹的路径,是完整的路径(绝对路径)
        System.out.println(f.getAbsolutePath());

        System.out.println(f5);// 打印文件的相对路径
        // 返回一个用当前的文件的绝对路径构建的file对象
        System.out.println(f5.getAbsoluteFile());

        // 返回当前文件/夹的父级路径,也就是文件的前面的完整路径,比如:D:\\abc\\abc.txt就是获取D:\\abc父级路径
        System.out.println(f.getParent());

        // 文件重命名
        f.renameTo(new File("D:/abc/rename.txt"));
        System.out.println("====================");
        
        
    // 2文件检测
        File f6 = new File("D:/abc/favicon.ico");
        // exists()判断文件/夹是否存在,返回布尔值
        System.out.println(f6.exists());

        // canWrite()判断文件/夹是否可写,canRead()判断文件/夹是否可读
        System.out.println(f6.canWrite());
        System.out.println(f6.canRead());

        // 判断当前的file对象是不是文件
        System.out.println(f6.isFile());
        // 判断当前的filed对象是不是文件夹/目录
        System.out.println(f6.isDirectory());

        // 获取文件最后修改的时间,返回的是一个毫秒数
        System.out.println(f6.lastModified());
        // 返回文件的长度,单位是字节数
        System.out.println(f6.length());
        System.out.println("====================");
        
        
    // 3文件/夹操作
        File f3 = new File("D:/abc/abc.txt");
        System.out.println(f3.exists());
        // 如果文件不存在,则创建
        if (!f3.exists()) {
            try {
                f3.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 删除文件
        f3.delete();

        File f2 = new File("D:/abc/cc");
        System.out.println(f2.exists());
        if (!f2.exists()) {
            // 创建单层目录,如果使用mkdir方法创建多层目录,只能一层层的执行mkdir方法
            f2.mkdir();
        }

        File f4 = new File("D:/abc/dd/aa/ee");
        if (!f4.exists()) {
            // 创建多层目录,注意是mkdirs(),上面的mkdir少了s
            f2.mkdirs();
        }

        File f7 = new File("D:/abc");
        // list()返回当前文件夹的子集的名称,包括目录和文件名
        String[] flist = f7.list();
        for (String name : flist) {
            System.out.println(name);
        }
        
        // listFiles()返回当前文件夹的子集的file对象,包括目录和文件名
        //就是返回子集里面所有的文件名/目录的绝对路径,例如: D:\\abc\\cc, D:\\abc\\favicon.ico
        File[] files = f7.listFiles();
        for(File file : files) {
            System.out.println(file);
        }
    }
}
View Code

递归遍历文件夹/文件

通常把某个文件夹里面的文件和目录全部遍历出来,不管层级有多深,但是不知道有多少层目录,就会导致遍历文件的代码会重复,因为每进入一个目录,就要遍历里面的文件和目录,下面举一个例子说明遍历文件夹所有文件/目录时,陷于重复代码。

import java.io.File;

public class Test2 {
    public static void main(String[] args) {
        
    }
    //递归的引出
    public void findAllFiles(File file) {
        if(file.isFile()) {
            System.out.println(file.getAbsoluteFile()+"是一个文件");
        }else {
            //是文件夹则继续遍历里面的文件和目录
            System.out.println(file.getAbsolutePath()+"是文件夹");
            //获取文件夹中的所有目录/文件,使用file数组接收
            File[] files = file.listFiles();
            //遍历数组里面的文件/目录
            for(File f : files) {
        //如果是文件则打印文件,      下面开始第一层重复
                if(file.isFile()) {
                    System.out.println(file.getAbsoluteFile()+"是一个文件");
                }else {
                    //如果是文件夹则继续遍历里面的文件和目录
                    System.out.println(file.getAbsolutePath()+"是文件夹");
                    //获取文件夹中的子集,包含文件/目录
                    File[] files2 = file.listFiles();
                    //遍历数组里面的文件/目录
                    for(File f2 : files) {
        //如果是文件则打印文件,   这里的下面是第二层重复
                        if(file.isFile()) {
                            System.out.println(file.getAbsoluteFile()+"是一个文件");
                        }else {
                            //如果是文件夹则继续遍历里面的文件和目录
                            System.out.println(file.getAbsolutePath()+"是文件夹");
                            //获取文件夹中的子集,包含文件/目录
                            File[] files3 = file.listFiles();
                            //然后继续遍历files3数组里面的文件和目录,如果是目录那么继续遍历
                            //这里就不重复写代码了,for循环后面都是一样的代码,这样一直遍历,不知道要写多少层,是死循环代码
        //下面是第三层重复代码,就不写了,如果是重复的代码,而且不知道写到几层,就应该使用递归方法。递归就是方法调用本身,方法调用自己
                        }
                    }
                }
            }
        }
    }
}
View Code

从上面的例子,可以发现for下面的代码就开始重复了,但是不知道要重复多少次,因为目录不知道有多少层,现在用递归来遍历。

import java.io.File;

public class Test3 {
    public static void main(String[] args) {
        //创建一个目录对象
        File file = new File("D:/abc");
        //然后把目录对象,传给findAllFiles()方法遍历该目录底下的所有层级的目录/文件
        new Test3().findAllFiles(file);
    }
    //递归遍历所有的目录/文件,每一层
        public void findAllFiles(File file) {
            if(file.isFile()) {
                System.out.println(file.getAbsoluteFile()+" 是一个file");
            }else {
                //是文件夹则继续遍历里面的文件和目录
                System.out.println(file.getAbsolutePath()+" 是一个文件夹");
                //获取文件夹中的所有目录/文件,使用file数组接收
                File[] files = file.listFiles();
                //遍历数组里面的文件/目录
                for(File f : files) {
                    //重点在这里,递归:自己调用自己,直到遍历完所有文件/目录,否则重复调用findAllFiles(f);
                    findAllFiles(f);
                }
            }
        }
    }
View Code

注意:递归需要有结束条件,如果没有结束条件会一直执行递归,直到内存溢出报异常。上面的例子的结束条件是目录数,目录是有限的,所以遍历完目录/文件就会结束递归。

 IO原理

iO流用来处理设备之间的数据传输。

Java程序中,对于数据的输入/输出操作以”流(stream)” 的方式进行。

java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

 IO流的分类

 

 IO流体系

 

FileInputStream 文件字节输入流

文件需要读取内容时,可以使用FileInputStream类,下面举一个例子说明FileInputStream类如何读取文件。

import java.io.FileInputStream;

public class Test4 {
    public static void main(String[] args) {
        Test4.readFile("D:/abc/rename.txt");
    }
    //读取文件的方法
    public static void readFile(String path) {
        try {
            //把文件转为输入流
            FileInputStream in = new FileInputStream(path);
            
            //设置byte数组接收读取的文件的内容
            byte[] b = new byte[10];
            
            //设置临时变量存储每次读取的长度,也就是in.read(10)返回的长度
            //肯定有人说为什么不直接使用in.read(10)的返回值,而是要新创建变量len去接收返回值再使用
            //因为每次执行in.read(b)方法时,都会读取一次文件,每次返回的值都不一样
            //比如下面的len = in.read(b)第一次返回10,但是你在循环体中输出in.read(b)的长度就不是10了,因为又执行了一遍读操作
            int len = 0;
            
            //因为byte数组固定了长度为10,所以需要循环读取文件,每次读取10个字符
            //补充:read()方法是读取一个字节,返回字节如果是字母就返回ASCII码,比如文件内容第一个字节是a就返回97
            //read(byte[] b)方法是返回每次读取字节数的个数,个数根据byte数组长度决定,所以下面使用read(byte[] b)方法,而不使用上面的read()方法
            while((len = in.read(b))!=-1) {
                System.out.println(len);
//                System.out.println(in.read(b));//这里注释掉了,如果想了解len变量为什么要存在,可以取消注释,测试一下
                //new String(缓冲的数组,数组里面的字符串转换起始坐标,每次转换的长度),这里是把每次读取的数据转为字符串输出
                System.out.println(new String(b,0,len));    
            }
            //每次读取数据都要关闭输入流,因为流操作的时候凡是跨出虚拟机边界的资源都要求程序员自己关闭,不要指望垃圾回收。
            in.close();//你读一个文件,忘记关闭了流,你在操作系统里对这个文件的写,删除等操作就会报错,告诉你这个文件被某个进程占用。
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

 

 FileOutputStream 文件字节输出流

文件需要写进数据时,可以使用FileOutputStream类,下面举一个例子说明FileOutputStream类如何对文件写入内容。

import java.io.FileOutputStream;

public class Test5 {
    public static void main(String[] args) {
        //传一个文件过去,写进数据
        Test5.writeFile("D:/abc/abc.txt");
    }
    public static void writeFile(String absoluteFile) {
        //创建输出流
        try {
            FileOutputStream out = new FileOutputStream(absoluteFile);
            //创建要写入的数据
            String str = "abcdefghijklmnopkrstuvwxyz";
            //把数据写入到输出流,因为OutputStream是二级制流,所以str需要转换为Byte类型才能写入到输出流
            out.write(str.getBytes());//把数据写入到内存
            out.flush();//把数据从内存刷进硬盘
            //关闭输出流
            out.close();
            
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

练习

把一个文件复制到另外一个目录去,利用FileInputStream和FileOutputStream来操作。

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test6 {
    public static void main(String[] args) {
        //sAbsoluteFile是要获取的文件路径,前面变量名的s是start
        String sAbsoluteFile = "D:/abc/a.jpg";
        //eAbsoluteFile是要输出的文件路径,前面变量首字母e是end
        String eAbsoluteFile = "D:/abc/cc/sui.jpg";
        //把sAbsoluteFile文件复制到eAbsoluteFile中去
        Test6.copyFile(sAbsoluteFile, eAbsoluteFile);
    }
    /**
     * 复制文件到指定位置
     * @param sAbsoluteFile 源文件路径
     * @param eAbsoluteFile    复制到文件夹位置
     */
    public static void copyFile(String sAbsoluteFile,String eAbsoluteFile) {
        try {
            //创建输入流获取要复制的文件内容,也就是要读取的源文件
            FileInputStream in = new FileInputStream(sAbsoluteFile);
            //创建输出流,输出到指定位置,也就是要复制到哪里
            FileOutputStream out = new FileOutputStream(eAbsoluteFile);
            //创建接收的数组
            byte[] b = new byte[100];
            //创建临时变量接收返回每次读取文件的长度
            int len = 0;
            //循环读取数据,注意read()方法和read(byte[] b)的区别,一个是返回字节,一个是返回每次读取字节的个数
            while((len = in.read(b)) != -1) {
                //把读取到的数据通过输出流写入
                out.write(b, 0, len);//把数据写入到内存
            }
            //把内存中的数据刷入硬盘
            out.flush();
            //关闭输出/输入流
            out.close();
            in.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

注意:文件字节流非常通用,可以用来操作字符的文档,还可以操作任何的其他类型文件(图片,压缩包等等),引用字节流直接使用二进制。字节流是通过二进制方式传输数据的。

FileReader文件字符输入流

字符输入流和字节输入流用法差不多,区别在于,一个是用于字节传输的方式,一个是字符传输的方式。唯一改变的就是临时数组字节流就采用byte[]数组,字符流就采用char[]数组。

最重要的区别:字节流可以传输类型比较多的文件,但是字符流只能传输文本文档,word文档虽然是文本文档,但是文档存在格式,虽然可以传输成功,但是文件会打不开。也就是只能支持txt类型文本。

import java.io.FileReader;

public class Test7 {
    public static void main(String[] args) {
        String inPath = "D:/abc/abc.txt";
        Test7.testFileReader(inPath);
    }
    
    /**
     *     文件字符输入流FileReader
     * @param inPath 源文件路径
     */
    public static void testFileReader(String inPath) {
        try {
            //创建文件字符输入流的对象
            FileReader fr = new FileReader(inPath);
            
            //创建临时存数据的字符数组
            char[] ch = new char[10];
            
            //定义临时变量存储每次读取数据的长度
            int len = 0;
            
            //循环遍历字符输入流
            while((len = fr.read(ch)) != -1) {
                System.out.println(new String(ch,0,len));
            }
            //关闭输入流
            fr.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
View Code

FileWriter文件字符输出流

字符输出流和字节输出流用法差不多,区别在于,一个是用于字节传输的方式,一个是字符传输的方式。

import java.io.FileWriter;

public class Test8 {
    
    public static void main(String[] args) {
        //传一个文件过去,写进数据
        Test8.TestFileWriter("D:/abc/abc.txt");
    }
    public static void TestFileWriter(String absoluteFile) {
        //创建输出流
        try {
            FileWriter out = new FileWriter(absoluteFile);
            //创建要写入的数据
            String str = "abcdefghijklmnopkrstuvwxyz";
            //把数据写入到输出流
            out.write(str);//把数据写入到内存
            out.flush();//把数据从内存刷进硬盘
            //关闭输出流
            out.close();
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
View Code

练习

把一个文件复制到另外一个目录去,利用FileReader和FileWriter来操作。

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Test9 {
    public static void main(String[] args) {
        String inPath = "D:/abc/abc.txt";
        String outPath = "D:/abc/cc/ss.txt";
        Test9.copyFile(inPath, outPath);
    }

    /**
     * 
     * @param inPath  源文件路径
     * @param outPath 传输到指定目录
     */
    public static void copyFile(String inPath, String outPath) {
        FileReader fr = null;
        FileWriter fw = null;
        
        try {
            // 创建字符输入流
            fr = new FileReader(inPath);
            // 创建字符输出流
            fw = new FileWriter(outPath);
            
            //创建临时数组接收数据
            char[] ch = new char[10];//因为是字符流所以使用char数组
            int len = 0;
            
            //循环遍历读取文件,然后写入到内存中
            while((len = fr.read(ch)) != -1) {
                fw.write(ch,0,len);
            }
            //把内存的数据刷入硬盘
            fw.flush();
        
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭流
            try {
                fw.close();
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
View Code

注意:

1、定义文件路径时,注意:可以用“/”或者“\\\\”。

2、在写入一个文件时,如果目录下有同名文件将被覆盖。

3、在读取文件时,必须保证该文件已存在,否则出异常。

 缓冲流

 

 没有缓冲流的时候,IO流的操作是“ 读一点文件,然后写入文件,再读一点文件,然后再写入文件 “。

举个例子说明缓冲流的作用:比如送快递,寄快递不可能是有人寄出了,就马上送,而是在一个时间点内,把当天的全部快递统一装车运输,这里面运输快递的就是相当于缓冲流

  IO流都是计算机与硬盘之间发送的io操作,基于硬盘的读写相对式比较慢,这个操作的速度受到硬盘的读写速度的约束,为了能够提高读写速度,一定程度上绕过硬盘的限制,Java提供一种缓冲流来实现。

  缓冲流就是先把数据缓冲到内存里,在内存中去做io操作,基于内存的io操作大概能比基于硬盘的io操作快75000多倍.

缓冲流不同的类对应不同的IO流类,不可混合使用缓冲流类。

BufferedInputStream——FileInputStream

BufferedInputStream——FileOutputStream

BufferedReader——FileReader

BufferedWriter——FileWriter

BufferedInputStream

BufferedInputStream是字节缓冲输入流。

例子

import java.io.BufferedInputStream;
import java.io.FileInputStream;

public class Test {
    public static void main(String[] args) {
        Test.testBufferedInputStream();
    }
    
    /**
     * 缓冲字节输入流
     *     BufferedInputStream
     */
    public static void testBufferedInputStream() {
        try {
            //文件字节输入流
            FileInputStream in = new FileInputStream("E:\\\\workspace-sts\\\\Test1\\\\src\\\\org\\\\chen\\\\day13\\\\tt.txt");
            //把文件字节输入流放到缓冲字节输入流,BufferedInputStream(InputStream类/子类)
            BufferedInputStream br = new BufferedInputStream(in);
            
            //创建临时数组接收数据,下面的注释就不写了,操作都差不多
            byte[] b = new byte[10];
            int len = 0;
            while((len = br.read(b)) != -1) {
                System.out.println(new String(b,0,len));
            }
            //关闭流的时候,本着一个最晚开的最早关,依次关闭
            br.close();//关闭缓冲流
            in.close();//关闭输入流
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

BufferedOutputStream

BufferedOutputStream是字节缓冲输出流。

例子

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;

public class Test2 {
    public static void main(String[] args) {
        Test2.testBufferedOutputStream();
    }
    
    /**
     * 缓冲字节输出流
     * BufferedOutputStream
     */
    public static void testBufferedOutputStream() {
        try {
        //创建输出流
        FileOutputStream out = new FileOutputStream("E:\\\\workspace-sts\\\\Test1\\\\src\\\\org\\\\chen\\\\day13\\\\tt.txt");
        //缓冲字节输出流
        BufferedOutputStream bos = new BufferedOutputStream(out);
        
        //把内容写入到文件中,注意写入的文件如果名字一样,内容会被覆盖
        String str = "需要被写入的内容。。。。。谢谢谢谢谢谢";
        //写入到内存中,write方法只能写入字节,所以str转换byte写入
        bos.write(str.getBytes());
        
        bos.flush();//刷到硬盘上
        //先开后关原则。
        bos.close();
        out.close();
        
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

练习

把一个文件复制到另外一个目录去,利用BufferedInputSream和BufferedOutputStream来操作。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test4 {
    public static void main(String[] args) {
        String inPath = "D:/abc/a.jpg";
        String outPath = "D:/abc/cc/tou.jpg";
        Test4.copyFile(inPath, outPath);
    }
    /**
     * 缓冲流实现文件的复制
     * @param inPath 源文件
     * @param outPath 复制到指定路径
     */
    public static void copyFile(String inPath,String outPath) {
        try {
        //创建输入流
        FileInputStream fs = new FileInputStream(inPath);
        //缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(fs);
        
        //创建输出流
        FileOutputStream fo = new FileOutputStream(outPath);
        //缓冲输出流
        BufferedOutputStream bos = new BufferedOutputStream(fo);
        
        //临时数组
        byte[] b = new byte[10];
        int len = 0 ;
        //循环读取缓冲输入流
        while((len = bis.read(b)) != -1) {

以上是关于14Java的IO流的主要内容,如果未能解决你的问题,请参考以下文章

java第14周实验(IO流)

14Java的IO流

14. 流文件和IO

毕向东_Java基础视频教程第20天_IO流(11~14)

BitmapFactory:无法解码流:java.io.FileNotFoundException

JAVA IO流读取图片的问题