Thinking in Java 第18章 Java I/O 系统(18.1-18.8)

//声明:部分内容引自《Java编程思想(第四版)》机械工业出版社

【File 类】

– 目录列表器。例:

package io;//: io/DirList.java
// Display a directory listing using regular expressions.
// {Args: "D.*\.java"}

import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * Created by JT on 2016/7/23.
 */
public class DirList {
    public static void main(String[] args) {
        File path = new File(".");  // 创建 File 对象
        String[] list; // 创建字符串数组
        if (args.length == 0)
            list = path.list(); // 如果指定目录为空,则 list 存储所有 path 指向的文件的文件名
        else
            list = path.list(new DirFilter(args[0])); // 如果指定目录不为空,则 list 存储所有 path 指向的文件中符合目录过滤器的文件的文件名
        Arrays.sort(list, String.CASE_INSENSITIVE_ORDER); // 将 list 中存储的内容按字母(不区分大小写)顺序排列
        for (String dirItem : list)
            System.out.println(dirItem); // 输出 list 中保存的内容
    }
}

class DirFilter implements FilenameFilter { // 目录过滤器
    private Pattern pattern; 

    public DirFilter(String regex) { // 构造方法,将 pattern 初始化为正则表达式编译后的结果
        pattern = Pattern.compile(regex);
    }

    public boolean accept(File dir, String name) { // 实现接口 FilenameFilter 中的 accept() 方法,
                                                   // 此方法必须接受一个代表某个特定文件所在目录的 File 对象,以及包含了那个文件名的一个 String。
                                                   // accept() 方法会使用一个正则表达式的 matcher 对象,来查看此正则表达式 regex 是否匹配这个文件的名字。
        return pattern.matcher(name).matches();
    }
}

DirFilter 是目录过滤器类,这个类存在的唯一原因就是要实现 accept() 方法。创建这个类的目的在于把 accept() 方法提供给 list() 使用,使 list() 可以回调 accept(),进而以决定哪些文件包含在列表中。因此,这种结构也常常称为回调。更具体的说,这是一个策略模式的例子,因为 list() 实现了基本的功能,而且按照 FilenameFilter 的形式提供了这个策略,以便完善 list() 在提供服务时所需的算法。因为 list() 接受 FilenameFilter 对象作为参数,这意味着我们可以传递实现了 FilenameFilter 接口的任何类的对象,用以选择(甚至在运行时)list() 方法的行为方式。策略的目的就是提供了代码行为的灵活性。

list() 方法会为此目录对象下的每一个文件名调用 accept(),来判断该文件是否包含在内,判断结果由 accept() 返回的布尔值表示。

【输入和输出】

– 存储和恢复数据。
例:

package io;//: io/StoringAndRecoveringData.java

import java.io.*;

/**
 * Created by JT on 2016/7/24.
 */
public class StoringAndRecoveringData {
    public static void main(String[] args) throws IOException {
        DataOutputStream out = new DataOutputStream(
                new BufferedOutputStream(
                        new FileOutputStream("Data.txt")
                )
        );
        out.writeDouble(3.14159);
        out.writeUTF("That was pi");
        out.writeDouble(1.41413);
        out.writeUTF("Square root of 2");
        out.close();
        DataInputStream in = new DataInputStream(
                new BufferedInputStream(
                        new FileInputStream("Data.txt")
                )
        );
        System.out.println(in.readDouble());
        // Only readUTF() will recover the
        // Java-UTF String properly:
        System.out.println(in.readUTF());
        System.out.println(in.readDouble());
        System.out.println(in.readUTF());
    }
}

PrintWriter 可以对数据进行格式化,以便人们的阅读。但是为了输出可供另一个“流”恢复的数据,我们需要用 DataOutputStream 写入数据,并用 DataInputStream 恢复数据。当然,这些流可以是任意形式,但该例使用的是一个文件,并且对于读和写都进行了缓冲处理。(因为 DataOutputStream 和 DataInputStream 是面向字节的,所以要使用 InputStream 和 OutputStream。)
如果我们使用 DataInputStream 写入数据,Java 保证我们可以使用 DataInputStream 准确地读取数据——无论读和写数据的平台多么不同。

【标准 I/O】

– 程序的所有输入都可以来自于标准输入,它的所有输出也都可以发送到标准输出,以及所有的错误信息都可以发送到标准错误标准 I/O 的意义在于:我们可以很容易地把程序串联起来,一个程序的标准输出可以成为另一程序的标准输入。

– 从标准输入中读取。
按照标准 I/O 模型,Java提供了 System.in、System.out、System.err。其中 System.out 和 System.err 已经事先被包装成了 printStream 对象,所以可以立即使用。System.in 是一个没有被包装过的未经加工的 InputStream,因此读取 System.in 之前必须对其进行包装。
例(直接回显输入的每一行):
通常,我们会用 readLine() 一次一行地读取输入,为此,我们将 System.in 包装成 BufferedReader 来使用,这要求我们必须用 InputStreamReader 把 System.in 转换成 Reader。

package io;//: io/Echo.java
// How to read from standard input.
// {RunByHand}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Created by JT on 2016/7/24.
 */
public class Echo {
    public static void main(String[] args) throws IOException {
        BufferedReader stdin = new BufferedReader(
                new InputStreamReader(System.in)
        );
        String s;
        while ((s = stdin.readLine()) != null && s.length()!=0)
            System.out.println(s);
    }
}

– 将 System.out 转换成 PrintWriter。、
Sytem.out 是一个 PrintStream, 而 PrintStream 是一个 OutputStream。PrintWriter 有一个可以接受 OutputStream 作为参数的构造器。因此,只要需要,就可以使用那个构造器把 System.out 转换成 PrintWriter。

例:

package io;//: io/ChangeSystemOut.java
// Turn System.out.PrintWriter.

import java.io.PrintWriter;

/**
 * Created by JT on 2016/7/24.
 */
public class ChangeSystemOut {
    public static void main(String[] args) {
        PrintWriter out =  new PrintWriter(System.out, true);
        out.println("Hello, world");
    }
}

重要的是要使用有两个参数的 PrintWriter 的构造器,并将第二个参数设为 true,以便开启自动清空功能,否则,你可能看不到输出。

– 标准 I/O 重定向。
如果我们突然开始在显示器上创建大量输出,而这些输出滚动得太快以至于无法阅读时,重定向输出就显得极为有用。

例:

package io;//: io/Redirecting.java
// Demonstrates standard I/O redirection.

import java.io.*;

/**
 * Created by JT on 2016/7/24.
 */
public class Redirecting {
    public static void main(String[] args) throws IOException {
        PrintStream console = System.out;
        BufferedInputStream in = new BufferedInputStream(
                new FileInputStream("Redirecting.java")
        );
        PrintStream out = new PrintStream(
                new BufferedOutputStream(
                        new FileOutputStream("test.out")
                )
        );
        System.setIn(in);
        System.setOut(out);
        System.setErr(out);
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in));
        String s;
        while ((s = br.readLine()) != null)
            System.out.println(s);
        out.close(); // Remember this!
        System.setOut(console);
    }
}

这个程序将标准输入附接到文件上,并将标准输出和标准错误重定向到另一个文件。其中注意,它在程序开头处存储了对最初的 System.out 对象的引用,并且在结尾处将系统输出恢复到了该对象上。
I/O 重定向操纵的是字节流,而不是字符流,因此我们使用的是 InputStream 和 OutoutStream,而不是 Reader 和 Writer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值