基础系列【十二】--IO流

本文深入讲解Java IO流的基础概念,包括输入输出流的分类、字节流与字符流的区别,以及FileWriter、FileReader等核心类的使用方法。探讨了流的异常处理策略,介绍了PrintStream、Scanner、Properties等高级流的特性,同时覆盖了序列化、反序列化及字符串流的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IO流

按照传输的方向:
    流具有方向性,将数据从外部位置传输给程序的流 称之为 输入流。
    将数据从程序输出给外部位置的流 称之为 输出流。

按照操作的数据:
    流中流动的数据,可以是 字节数据 或 字符数据。
    字节流动起来组成的流称之为 字节流。
    字符流动起来形成的流称之为 字符流。 
    **注意:字符流的底层仍然是字节流,只不过字符传输的需求非常的常见,所以专门提供了 直接操作字符的流,看起来操作的是字符,其实底层仍然是将字符转换为字节来处理的。

java.io     输入流         输出流
----------------------------------------
字节流 |   InputStream  | OutputStream
字符流 |   Reader       | Writer
-----------------------------------------

**以上四大流,都是抽象类,无法直接使用,java提供了以上四种基本流的类的具有具体功能的子类,我们平常用的都是具体子类。
**目的地包括但不限于: 文件、网络、内存、控制台 等等。。

字符输出流 - Writer

案例:从程序中利用字符输出流向文件中写出数据
    输出 -- 输出流  字符数据 -- 字符流
    字符输出流 - Writer
    操作的是文件 - Writer - OutputStreamWriter - FileWriter


1.FileWriter的构造方法
    FileWriter(File file) //接受一个File对象 创建到指定file对象代表的文件的字符输出流 输出数据时 默认覆盖文件中的数据
    FileWriter(File file, boolean append) //额外接收一个布尔类型的参数 指定是否要以追加数据的方式执行写出
    FileWriter(String fileName) //接受一个文件的路径字符串 创建到指定路径文件的字符输出流 输出数据时 默认覆盖文件中的数据
    FileWriter(String fileName, boolean append) //额外接收一个布尔类型的参数 指定是否要以追加数据的方式执行写出

    **如果创建流时文件已经存在则连接到该文件进行操作
    **如果创建流时文件不存在,则自动创建该文件并连接到该文件进行操作
    **如果指定的位置不可到达 或 没有对应权限进行操作,则抛出IOException

2.输出相关的方法
    void write(int c)  
    void write(char[] cbuf)  
    void write(char[] cbuf, int off, int len) 
    void write(String str)  
    void write(String str, int off, int len)  

    **write方法写出数据时 并不会直接将数据写出到外部设备中 而是会在流内做缓冲 来提升操作效率,但是这样的方式 可能造成 数据并不能立即写出当程序意外 退出时可能造成 部分数据 残留在缓冲区中 丢失数据。

3.刷新流
     void flush() // 刷新缓冲区 将缓冲区中残留的数据 写出到目的地中

4.关闭流
     void close()  //关闭流

     **流用完后一定要关闭,否则流会一直存在,一方面浪费程序内存资源,另一方面占用着文件,使文件无法被正常操作。
     **close操作会自动做一次flush 在关闭流之前 将缓冲区中的数据 刷出到目的地中。
/*
 * IO
 * 案例:利用字符输出流向文件写出数据
 */
public class IOExr {
public static void main(String[] args) throws IOException {
    //FileWriter:向文件中写入字符。
    // FileWriter(File file):根据给定的 File 对象构造一个 FileWriter 对象。
    // FileWriter(File file, boolean append):根据给定的 File 对象构造一个 FileWriter 对象,并以追加的形式写入文件。。
    // FileWriter(String fileName):根据给定的文件名构造一个 FileWriter 对象。
    // FileWriter(String fileName, boolean append):根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

    FileWriter fw = new FileWriter("D:\\1.txt");//文件不存在,则创建。若文件路径不可达,或者没有访问权限,则抛IOException
    /*
     * writer相关的方法:
     * writer(int c);
     * write(char[] buf);
     * write(char[] cbuf, int off, int len);
     * writer(String str);
     * write(String str,int off,int len);
     * 注意:在使用writer方法向文件写数据的时候,会先将数据写入到缓冲区中,来提高效率。
     *      但是可能会出现程序结束之后,缓冲区的数据并没有将数据全部写入到文件中。
     *      因此我们提供void flush() --将缓冲区的的数据写入到文件中。
     * 注意2:流用完后一定要关闭,否则,在程序运行期间,一直会占用该文件(不能再针对此文件进行其他的操作),浪费资源。

     */
    fw.write("abcd");//没有写入权限的时候会抛异常
    fw.flush();// 再写出的时候,发生了意外操作(U盘被拔出),找不到刷新的目的地。
    fw.close();// 若在close()前面的代码发生了异常,此close()可能不执行,所以,一般释放资源的操作,需放在finally里面

}
}

流的异常处理

FileWriter writer = new FileWriter("D:\\1.txt",true); //当指定的位置不存在 或 没有权限访问时 则抛出IOException
writer.write("abcd");//文件没有访问权限 则抛出IOException
writer.flush();//当要flush时因为一些意外情况造成flush失败 抛出IOException
writer.close();//当要close时因为一些意外情况造成close失败 抛出IOException

异常的处理是IO操作时必然遇到的问题

//1.close要在finally里执行 所以在本地trycatchfinally处理
//2.为了让writer可以在finally被访问到 所以讲 writer 外置定义
FileWriter writer = null;
try {
    writer = new FileWriter("D:\\1.txt",true);
    writer.write("abcd");
    int i = 1/0;
    writer.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    //3.因为wirter可能为null 为了防止空指针异常 在此处判断非空
    if(writer != null){
        //4.因为close方法也有可能抛出异常 捕获处理
        try {
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }  finally {
            //5.因为close异常时 可能没有正常关闭 
            //所以此处讲只用置为null 则对象失去所有引用  变为垃圾 
            //有机会被垃圾回收器回收 在回收时被关闭
            writer = null;
        }
    }
}

字符输入流 - Reader

案例:从程序中利用字符输入流从文件中读取数据
    读取 -- 输入流  字符数据 -- 字符流
    字符输入流 - Reader
    操作的是文件 - Reader - InputStreamReader - FileReader

1.FileReader的构造方法
    FileReader(File file)//接受一个File对象 创建到指定file对象代表的文件的字符输入流 
    FileReader(String fileName)//接受一个文件的路径字符串 创建到指定路径文件的字符输入流

    **如果指定的位置不可到达 或 没有对应权限进行操作,则抛出IOException

2.输入相关的方法
    read() 
    read(char[] cbuf, int offset, int length) 
    read(char[] cbuf) 
    read(CharBuffer target)

    **read()方法 返回的是一个int值 为什么不直接返回一个char?因为无法用一个特定的 char来表示文件读到结尾的情况 -- 无论返回什么都会有歧义,到底是文件结尾了还是真的文件里就是这个字符 --  所以 用了 4个字节的int作为返回值,如果正常的读取到一个字符数据,则 在int的后两位保存该字节数据 并保证该int为一个正数,这样直接将int强转为char就可以读取到正确的字符,而当文件到达结尾时 返回一个特定值 -1 表示文件到达了结尾。

3.关闭流
     void close()  //关闭流

     **流用完后一定要关闭,否则流会一直存在,一方面浪费程序内存资源,另一方面占用着文件,使文件无法被正常操作。
如何决定选择什么流呢? 
1.当前数据是输入程序还是从程序中输出
2.要输出的数据是否是字符数据,如果不是字符数据必须用字节流,如果是字符数据可以用字节流也可以用字符流,推荐使用字符流,可以省去自己进行字节字符转换的操作。
3.考虑数据的目的地是什么,从四大基本流的继承结构中找寻对应的能使用的流。
4.考虑是否需要提高效率,如果需要可以通过Buffered.....来包装一把。

/*
 * IO
 * 案例:利用字符流从文件读取数据
 */
public class IOExr3 {
public static void main(String[] args) {
    FileReader fr = null;
    try {
        fr = new FileReader("D:\\1.txt");// 文件不存在,则创建。若文件路径不可达,或者没有访问权限,则抛IOException
        int i = -1;
        while ((i = fr.read()) != -1) {
            // fr.read();//读取一个字符
            System.out.println((char) i);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fr != null) {
            try {
                fr.close();// 若在close()前面的代码发生了异常,此close()可能不执行,所以,一般释放资源的操作,需放在finally里面
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                fr = null;
            }
        }
    }
}
}

//案例;通过BufferedReader和BufferedWriter实现缓冲高效读写数据
public class IOExr4 {
public static void main(String[] args) {
    FileReader reader = null;
    FileWriter writer = null;
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        reader = new FileReader("E:\\1.txt");
        br = new BufferedReader(reader);        
        writer = new FileWriter("E:\\2.txt");
        bw = new BufferedWriter(writer);

        // 底层通过缓冲数组 char[]
        int i = -1;
        while((i=br.read())!=-1){
            bw.write(i);
        }
        bw.flush();
        /*// 自定义缓冲数组
        char[] cs  = new char[1024];
        int i = -1;
        while ((i = reader.read(cs)) != -1) {
            writer.write(cs,0,i);
        }
        writer.flush();*/
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (br!=null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                br = null;
            }
        }
        if (bw!=null) {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                bw = null;
            }
        }
        /*if (reader!=null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                reader = null;
            }
        }
        if (writer!=null) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                writer = null;
            }
        }*/
    }
}
}

IO流中基本的流

1. 字节输入流:以字节为单位,操作数据,可以操作任何形式的数据
1. InputStream(所有直接输入流的父类(抽象))
    1. FileInputStram
                构造方法:
                    FileInputStream(File file) 

                    FileInputStream(String name) 
                方法:
                     int read() 
                     int read(byte[] b) 
                     int read(byte[] b, int off, int len) 
    2. 自带缓冲区的流
        1. FileInputStream--BufferedInputStream
        2. OutputStream - FilterOutputStream - BufferedOutputStream
            1. 构造方法:
                BufferedInputStream(OutputStream out) 
                BufferedInputStream(OutputStream out, int size) 
                BufferedOutputStream(OutputStream out) 
                BufferedOutputStream(OutputStream out, int size)
            2. 利用了装饰设计模式 传入流 自动增加缓冲功能 

    2. ObjectInputStream

2. 字节输出流

6. 系统流:当前系统对接的标准输出流中(默认控制台)读写数据
    System.out -- 标准输出流 
    System.err -- 标准错误输出流
    System.in -- 标准输入流
    **可以通过setIn(InputStream in) setOut(PrintStream out) 来修改标准流 的对应的位置
/*
 * 系统流:当前系统对控制的输出输入的操作
 */
public class Exr3 {
    public static void main(String[] args) throws IOException {
//      OutputStream out = System.out;
//      byte[] bs = "lalal".getBytes();
//      out.write(bs);
        // 系统输出流实际上是一个PrintStream
    PrintStream out = System.out;
    out.print("hello io~");
    out.println("hello io~");
    out.printf("my name is %s\r\n", "小王");//my name is 小王
    // 标准错误输出流
    PrintStream err = System.err;
    err.println("c");//控制台字符变红
    // 标准输入流
    InputStream in = System.in;
    byte[] data = new byte[1024];
    int len = in.read(data);
    System.out.println(new String(data,0,len));//21sakjfdadsfjk   21sakjfdadsfjk
    // 利用转化流便捷读取行
    BufferedReader br = new BufferedReader(new InputStreamReader(in));
    String line = null;
    while ((line = br.readLine())!=null) {
        System.err.println(line);
    }
}
}

PrintStream - 打印流

 OutputStream - FilterOutputStream - PrintStream

    为其他流量增加了按照特定格式打印输出数据的功能。
    另外能够保证:
        永远不抛异常
        自动flush

    构造方法:
        PrintStream(File file) 
        PrintStream(String fileName) 
        PrintStream(OutputStream out) 

    其他方法:
        各种print方法 输出各种类型的数据
        各种println方法 输出各种类型的数据 并在其后换行
        printf方法 输出格式化字符串

转换流

 转换流,可以将字节流转换为字符流,本质上就是在字节流的基础上 通过 装饰设计模式 增加了 编解码的功能 从而可以以字符为单位来输入输出数据。
    Reader - InputStreamReader - 将字节输入流转换为字符输入流
        构造方法:
            InputStreamReader(InputStream in)//不指定码表默认使用当前平台码
            InputStreamReader(InputStream in, Charset cs)//也可是手动指定码表
            InputStreamReader(InputStream in, String charsetName)//也可是手动指定码表

        案例:利用FileReader读取一个UTF-8的文本文件
            发现FileReader默认按照平台码读取文件 当读取其他码表文件时 会乱码
            如果想要解决这个乱码 FileReader做不到 需要自己来通过InputStreamReader来构建特定编码机的字符输入流

        案例:利用InputStreamReader来创建一个可以读取任意编码集文件的字符输入流
        Writer - OutputStreamWriter - 将字节输出流转换为字符输出流
    案例:用FileWriter输出数据到文件中 观察文件的编码集
        发现输出的文件默认是gbk(平台码) 且无法修改
        如果想要按照指定编码来输出数据 需要 创建字节输出流 再通过转换流 转换为字符流 再在这个过程中指定编码

    案例:用转换流 转换 文件字节输出流 为字符流 且指定编码输出数据

Scanner的用法

 Scanner
java.util.Scanner 扫描器类 可以对输入的内容做扫描操作

构造方法:
    Scanner(File source)//以文件作为源来进行扫描
    Scanner(File source, String charsetName) //以文件作为源来进行扫描 可以指定编码集
    Scanner(InputStream source) //以流作为源来进行扫描
    Scanner(InputStream source, String charsetName) //以流作为源来进行扫描 可以指定编码集
    Scanner(String source) //以字符串为源来进行扫描

其他方法:
    useDelimiter(regex)//默认使用空格作为分隔符 处理输入 切为多个子串来进行扫描 可以通过此方法 配置 接受正则表达式作为分隔符
    各种hasNext方法,判断后续是否有指定类型的数据
    各种next方法,扫描后续的数据
    close方法 关闭扫描器 
    findInLine(regex) 接受正则表达式 匹配语句 获取匹配的子串

**通过scan从控制台读取数据
    Scanner scan = new Scanner(System.in);
    String line = scan.nextLine();
public static void main(String[] args) throws IOException {
    /*
     * 构造方法:
     *  Scanner(String source);
     *  Scanner(File source);
     *  Scanner(InputStream source);
     */
    Scanner s = new Scanner("my name is w age 15 18");
    // 从指定字符串扫描,默认按空格分割
    while(s.hasNext()){
        System.out.println(s.next());
        /*
         *  my
            name
            is
            w
            age
            15
            18
        */
    }
    // 可以指定分割符:按照字符分割
    /*s.useDelimiter("\\d");
    while (s.hasNext()) {
        System.out.println(s.next());//my name is w age 
    }*/

    // 通过正则匹配子串
    String str = s.findInLine("\\w+\\s\\d+");
    System.out.println(str);
    //从控制台按行读
    /*BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String str = br.readLine();
    System.out.println(str);*/


}

properties

//java.util.HashTable---java.util.Properties:线程安全的类,多个线程可以共享。
/*
 * 表示可以存储磁盘中的properties文件中的键值对集合。properties可以方便的写入流和从流中读取。
 * 注意: 文件的键和值都是字符串。
 *      Properties继承HashTable,可以使用put和putAll方法,但不建议,因为put等方法允许插入非String类型的键和值
 *      建议使用该类对象的setProperties(String key,String value)方法
 * 构造函数:
 *      public Properties() 创建一个无默认值的空属性列表。
 * 相关方法:
 *      //加载properties文件
 *      void load(Reader reader);
 *      void load(Reader reader);
 *      //获取文件的键值对
 *      String getProperty()
 *      设置 文件的键值对
 *      Object setProperty(String key, String value) 
 *      遍历文件的键
 *      Set<String> stringPropertyNames()
 *       
 *      public void store(OutputStream out,String comments)
 *  
 */
public class Prop {
public static void main(String[] args) throws FileNotFoundException, IOException {
    Properties prop = new Properties();
    prop.load(new FileInputStream("prop.properties"));
    System.out.println(prop.getProperty("name"));
    //新增属性到prop中
    prop.setProperty("gender", "男");
    prop.put("那", "la");
    //遍历文件的键
    Set<String> keys = prop.stringPropertyNames();
    for (String string : keys) {
        System.out.println(prop.getProperty(string));
    }
    //将prop中的数据写入到properties中
    prop.store(new FileOutputStream("prop.properties"), null);
}
}

序列化和反序列化

/*
 * 序列化--将内存中的对象信息转化为字节,目标是让对象可以持久储存。
 * 持久化:将内存中易失的对象信息,序列化后,保存到磁盘中,持久保存。
 * 序列化:将对象转字节的过程。
 * 序列化是持久化的前提,持久化是序列化的目标之一。
 * 注意点:想要实现序列化和反序列化的类,必须实现 Serializable接口。
 *       改接口没有任何方法和属性,仅仅作为一个标志,要求能狗屎序列化的类
 *       作为特定的标记,告知虚拟机,告诉该类的对象可以序列化。
 * 关键字:
 *      transient :在序列化的过程中的,忽略有该关键字的属性,不会被序列化。
 * serialVersionUID:根据此版本号判定两个类是否是同一个类。
 * 构造方法:
 *      ObjectOutputStream(OutputStream out) :装饰者模式  
 * 常用方法:
 *       void writeObject(Object obj)  将指定的对象写入 ObjectOutputStream。
 *       void flush();
 *       void close();
 * ===================================================================
 * 反序列化:
 * 构造放法:
 *       ObjectInputStream(InputStream in) 
 * 其他方法:
 *       Object readObject() 从 ObjectInputStream 读取对象。 
 */
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
transient private String password;

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

@Override
public String toString() {
    return "Person [name=" + name + ", age=" + age + ", password=" + password + "]";
}

public static void main(String[] args) throws Exception {

    // 序列化
    Person p = new Person();
    p.setName("小白");
    p.setAge(18);
    p.setPassword("12345");
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
    oos.writeObject(p);
    oos.flush();
    oos.close();

    // 反序列化
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
    Person p1 = (Person) ois.readObject();
    System.out.println(p1);
    ois.close();

}

ByteArrayInputStream ByteArrrayOutputStream

java.io.ByteArrayInputStream - 以字节数组为目标的字节输入流
    构造方法:
        ByteArrayInputStream(byte[] buf) 
        ByteArrayInputStream(byte[] buf, int offset, int length) 

    其他方法:
        int read()  
        int read(byte[] b, int off, int len) 
        close()

java.io.ByteArrrayOutputStream
    构造方法:
        ByteArrayOutputStream() 
        ByteArrayOutputStream(int size) 

    其他方法:
        byte[] toByteArray()
        void write(int b)  
        void write(byte[] b, int off, int len)    
        flush()
        close()//关闭效果无效
public static void main(String[] args) throws Exception {
    FileInputStream fis = new FileInputStream("E:\\1.txt");
    //内部维护一个缓冲数组,将读取的数据先写到内存数组里
    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    int i= -1;
    byte[] data = new byte[1024];
    while((i=fis.read(data))!=-1){
        bos.write(data,0,i);
    }
    bos.flush();
    fis.close();
    //该操作写不写都可以,因为bos没有连接任何文件
    bos.close();
    //将内存缓冲数据转化为数组
    byte[] bs = bos.toByteArray();
    String str = new String(bs,"gbk");

    bs = str.getBytes("GBK");
    FileOutputStream fos = new FileOutputStream("E:\\2.txt");
    fos.write(bs);
    fos.flush();
    fos.close();
}

字符串流和合并流

/*
 * Reader--StringReader:以字符串为数据来源的字符的输入流
 * 构造方法;
 *      StringReader(String s) 创建一个新字符串 reader。
 * 其他方法;
 *       int read() 读取单个字符 
 *       int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
 * 
 * Writer--StringWriter:以字符串为数据的目的地的输出流
 * 构造方法:
 * 其他方法:
 *      StringWriter append(char c)  将指定字符添加到此 writer
 *      void flush() 刷新该流的缓冲。 
 *      StringBuffer getBuffer() 返回该字符串缓冲区本身。
 *      String toString()  以字符串的形式返回该缓冲区的当前值。 
 *      void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 
 *      void write(int c)  写入单个字符。 void write(String str) 写入一个字符串。 
 *      void write(String str, int off, int len) 
 * SquenceInputStream--合并流
 * 构造方法:
 *  SequenceInputStream(Enumeration<? extends InputStream> e) 
 *              通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。 
 *  SequenceInputStream(InputStream s1, InputStream s2)  
 *              通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。 
 * 其他方法:
 * 合并流案例:将多个个文件合并为一个文件
 */
public class StringReaders {
public static void main(String[] args) throws Exception {
    String str = "小鸡吃米图";
    StringReader r = new StringReader(str);
    //System.out.println((char)r.read());//小
    int i = -1;
    while ((i = r.read())!=-1) {
        System.out.println((char)i);
    }
    r.close();
    StringWriter sw = new StringWriter();
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String line = br.readLine();//我气你四
    sw.write(line);
    line = br.readLine();//嘎嘎

    sw.write(line);

    sw.flush();
    sw.close();
    System.out.println(sw.toString());//我气你四嘎嘎

    // 创建文件读取流
    FileInputStream fis1 = new FileInputStream("1.txt");
    FileInputStream fis2 = new FileInputStream("2.txt");
    FileInputStream fis3 = new FileInputStream("3.txt");

    // 创建文件合并流
    Vector<FileInputStream> v = new Vector<>();
    v.add(fis1);
    v.add(fis2);
    v.add(fis3);
    SequenceInputStream sis = new SequenceInputStream(v.elements());
    // 创建输出流
    FileOutputStream fos = new FileOutputStream("4.txt");

    // 对接流
    int d= -1;
    byte[] bs = new byte[1024];
    while ((d=sis.read(bs))!=-1) {
        fos.write(bs,0,d);
    }
    // 关闭流
    sis.close();
    fos.close();

}
}
/*
 * 需求分析:
 * 统计工作空间中java文件的数量,和java代码的行数
 * 已有信息:
 * 工作空间的位置:D:\\WorkSpace
 * 步骤:
 *      遍历工作空间的的所有的文件和子文件夹
 *      如果是文件则文件数++,并读取文件的行数,行数++
 *      如果不是,则忽略。
 *      如果是子文件夹
 *          则进入子文件夹,重复以上步骤
 */
public class Exr {
static int javaFileCount;
static int javaLine;

public static void main(String[] args) {
    // 创建file对象
    File file = new File("D:" + File.separator + "WorkSpace");
    //
    mx(file);
    System.out.println(javaFileCount);
    System.out.println(javaLine);

}

static void mx(File file) {
    if (file == null) {
        throw new RuntimeException("文件不存在");
    }
    if (file.isDirectory()) {
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.isDirectory()) {
                mx(f);
            }else if (f.isFile()) {
                //
                if (f.getName().endsWith(".java")) {
                    javaFileCount++;
                    //
                    BufferedReader br = null;
                    try {
                        br = new BufferedReader(new FileReader(f));
                        while (br.readLine() != null) {
                            javaLine++;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (br!=null) {
                            try {
                                br.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            } finally {
                                br = null;
                            }
                        }
                    }

                }
            } else{
                continue;
            }
        }
    } 
}
}

下一篇:
基础系列【十三】–集合

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值