《Thinking in Java》学习——18章Java I/O系统(一)

File类

1.File(文件)类,我们 可能会认为它指代对事文件,实际上却并非如此。它既能代表一个特定的文件对名称,又能代表一个目录下的一组文件的名称

一.目录列表器

1.假设我们想要查看一个目录列表,可以用两种方法来使用File对象,如果我们调用不带参数的list()方法,便可获得此File对象包含的全部列表。然而,如果我们想获得一个受限列表,那么我们就要用到“目录过滤器”,这个类会告诉我们怎样显示符合条件的File对象:

public class DirList() {
    public static void main(String... args) {
        File path = new File(".");
        String[] list;
        if (args.length == 0) {
            list = path.list();
        } else {
            list = path.list(new DirFilter(args[0]));
        }
        for (String dirItem : list)
            System.out.println(dirItem);
    }
}

class DirFilter implements FilenameFilter {
    private Pattern pattern;
    public DirFilter(String regex) {
        pattern = Pattern.compile(regex);
    }
    public boolean accept(File dir, String name) {
        return pattern.matcher(name).matches();
    }
}

这里我们实现了FilenameFilter接口:

public interface FilenameFilter {
    boolean accept(File dir, String name);
}

accept()方法必须接受一个代表某个特定文件所在的目录的File对象,以及包含了那个文件名的一个String。list()方法会为此目录对象下的每个文件名调用accept()方法,来判断文件是否包含在内;判断结果由accept()返回的布尔值表示。

二.目录实用工具
public final class Directory {
    public static File[] local(File dir, String regex) {
        return dir.listFiles(new FilenameFilter() {
            private Pattern pattern = Pattern.compile(regex);
            public boolean accept() {
                return pattern.matcher(new File(name).getName()).matches();
            }
        })
    }

    public static File[] local(String path, final String regex) {
        return local(new File(path), regex);
    }

    public static TreeInfo walk(String start, String regex) {
        return recurseDirs(new File(start), regex);
    }

    public static TreeInfo walk(File start, String regex) {
        return recurseDirs(start, regex);
    }

    public static TreeInfo walk(File start) {
        return recurseDirs(new File(start), ".*");
    }

    public static TreeInfo walk(String start) {
        return recurseDirs(new File(start), ".*");
    }

    static TreeInfo recurseDirs(File startDir, String regex) {
        TreeInfo result = new TreeInfo();
        for (File item : startDir.listFiles()) {
            if (item.isDirectory()) {
                result.dirs.add(item);
                result.addAll(recurseDirs(item, regex));
            } else {
                if (item.getName().matches(regex)) {
                    result.files.add(item);
                }
            }
        }
        return result;
    }
    
    public static class TreeInfo implements Iterable<File> {
        public List<File> files = new ArrayList<File>();
        public List<File> dirs = new ArrayList<File>();
        
        public Iterator<File> iterator() {
            return files.iterator();
        }

        void addAll(TreeInfo other) {
            files.addAll(others.files);
            dirs.addAll(others.dirs);
        }
    }
}

在这里我们定义了一个工具类Directory,其中包含了两个方法:local()方法用来产生由本地目录中的文件构成的File对象数组;walk()方法产生给定目录下的由整个目录树中所有文件构成的List<File>。至于上面程序中使用到的关于File类的方法,根据方法名我们就能看出它们的用处。

三.目录的检查及创建

1.File类不仅仅只代表存在的文件或目录。也可以用File对象来创建新的目录或尚不存在的整个目录路径。我们还可以查看文件的特性,检查某个FIle对象代表的事一个文件还是一个目录,并可以删除文件。具体用法不再一一举出。

输入和输出

1.是个抽象的概念,它代表任何由能力产出数据的数据源对象或者是有能力接收数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。
2.通过继承,任何自InputStreamReader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何自OutputStreamWriter派生而来的类都含有名为write()的方法名,用于写单个字节或者字节数组。
3.使用的特点:创建单一的结果流,却需要创建多个对象。

一.InputStream类型

1.InputStream的作用是用来表示那些从不同数据源产生输入的类。每一种数据源都有相应的InputStream子类:

功能 构造器参数及使用
ByteArrayInputStream 允许将内存的缓冲区当做InputStream使用 缓冲区子节将从中取出;作为一种数据源:将其与FilterInputStream对象相连以提供有用的接口
StringBufferInputStream String转换成InputStream 字符串。底层实现实际使用StringBuffer;作为一种数据源:将其与FilterInputStream对象相连以提供有用的接口
FileInputStream 用于从文件中读取信息 字符串,表示文件名、文件或FileDescription对象;作为一种数据源:将其与FilterInputStream对象相连以提供有用的接口
PipedInputStream 产生用于写入相关PipedOutputStream的数据。实现“管道化” PipedOutputStream;作为一种数据源:将其与FilterInputStream对象相连以提供有用的接口
SequenceInputStream 将一个或多个InputStream对象转换成单一InputStream 两个InputStream对象或一个容纳InputStream对象的容器Enumeration;作为一种数据源:将其与FilterInputStream对象相连以提供有用的接口
FilterInputStream 抽象类,作为“装饰器”的接口。其中“装饰器”为其他的InputStream类提供有用的功能 见后续内容
二.OutputStream类型

1.该类别的类决定了输出所要去往的目标:

功能 构造器参数及使用
ByteArrayOutputStream 在内存中创建缓冲区。所有送往“流”的数据都要放置在此缓冲区 缓冲区初始化尺寸(可选);用于指定数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
FileOutputStream 用于将信息写至文件 字符串,表示文件名、文件或FileDescription对象;指定数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
PipedOutputStream 任何写入其中的信息都会自动作为相关PipedInputStream的输出。实现“管道化”的概念 PipedInputStream;指定用于多线程的数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
FilterOutputStream 抽象类,作为“装饰器”的接口。其中“装饰器”为其他的OutputStream类提供有用的功能 见后续内容

添加属性和有用的接口

1.FilterInputStreamFilterOutputStream是用来提供装饰器类接口以控制特定输入流河输出流的两个类,着两个类是装饰器的必要条件。

一.通过FilterInputStream从InputStream中读取数据

1.FilterInputStream类能够完成两种不同的事情:第一种是DataInputStream,这种类允许我们读取不同基本类型数据以及String对象,搭配相应的DataInputStream,我们就可以将基本类型的数据从一个地方迁移到另一个地方;另一种则在内部修改FilterInputStream的行为方式:是否缓冲,是否保留它所读过的行,以及是否把单一字符推回输入流等等:

功能 构造器参数及使用
DataInputStream DataOutputStream搭配使用,因此我们可以按照可移植的方式从流读取基本数据类型 InputStream;包含读取基本类型数据的全部接口
BufferedInputStream 使用它可以防止每次读区时都得进行实际写操作。代表“缓冲区” InputStream,可以指定缓冲区的大小(可选);本质上不提供接口,只不过是向进程中添加缓冲区所必需的。与接口对象搭配
LineNumberInputStream 跟踪输入流中的行号;可调用getLineNumber()和setLineNumber(int)** InputStream;仅增加了行号,因此可能要与接口对象搭配使用
PushbackInputStream 具有“能弹出一个字节的缓冲区”。因此可以将独岛的最后一个字符回退 InputStream;通常作为编译器的扫描器,之所以包含在内是因为Java编译器的需要,我们可能永远不会用到
二.通过FilterOutputStream向OutputStream写入

1.DataOutputStream与上面的DataInputStream相对应。
2.PrintStream的目的便是为了以可视化的格式打印所有的基本数据类型以及String对象。内部有两个重要的方法:print()println()。对它们进行了重载,以便打印出各种数据类型。
3.BufferedOutputStream,它对数据流使用缓冲技术;因此当每次向流写入时,不必每次都进行实际的物理写动作。

功能 构造器参数及使用
DataOutputStream DataInputStream搭配使用,因此我们可以按照可移植的方式从流写入基本数据类型 OutputStream;包含用于写入基本数据类型的全部接口
PrintStream 用于产生格式化输出。其中DataOutputStream处理数据的存储,PrintStream处理显示 OutputStream,可以用boolean值指示是否在每次换行时清空缓冲区
BufferedOutputStream 使用它以避免每次发送数据时都要进行实际的写操作。代表“使用缓冲区”。可以调用flush()清空缓冲区 OutputStream,可以指定缓冲区的大小(可选);本质上并不提供接口,只不过是向进程中添加缓冲区所必需的。与即可哦哭对象搭配

Reader和Writer

1.InputStreamOutputStream在以面向字节形式的I/O中可以提供极有价值的功能,ReaderWriter则提供兼容Unicode与面向字符的I/O功能。
2.InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer。这样就可以把来自于“字节”层次结构中的类和“字符”层次结构中的类结合起来使用。

一.数据的来源和去处

1.在使用I/O流的时候,最明智的做法是尽量尝试使用ReaderWriter,一旦程序代码无法编译成功,就不得不使用面向字节的类库。
2.下面的表中展示了各种两种不同层次结构中,信息的来源和去处的对应关系:

字节类Java 1.0 相应的字符类Java 1.1
InputStream Reader;适配器:InputStreamReader
OutputStream Writer;适配器:OutputStreamWriter
FileInputStream FileReader
FileOutputStream FileWriter
StringBufferInputStream(已弃用) StringReader
(无相应的类) StringWriter
ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter
PipedInputStream PipedReader
PipedOutputStream PipedWriter
二.更改流的行为

1.在更改“流”的行为方面,WriterReader的类继承层次结构继续沿用了和InputStreamOutputStream的思想——使用“装饰器”来修改“流”的特殊需要:

过滤器Java 1.0 相应的Java 1.1类
FilterInputStream FilterReader
FilterOutputStream FilterWriter(抽象类, 没有子类)
BufferedInputStream BufferedReader(也有readLine()
BufferedOutputStream BufferedWriter
DataInputStream 使用DataInputStream(除了当需要使用readLine()时以外,这时应该使用BufferedReader
PrintStream PrintWriter
LineNumberInputStream(已弃用) LineNumberWriter
StreamTokenizer StreamTokenizer(使用接受Reader的构造器)
PushbackInputStream PushbackReader

2.上面的表中已经指出:无论何时使用功能readLine(),都不应该使用DataInputStream,而应该使用BufferedReader。除此以外,DataInputStream仍然是I/O库的首选。

三.未发生变化的类
未作出改变的类
DataInputStream
File
RandomAccessFile
SequenceInputStream

特别是DataInputStream,在使用时没有人和变化;因此如果想以“可传输到”格式存储和检索数据,可以使用InputStreamOutputStream继承层次结构。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 一、流的概念和作用。 流是一种有顺序的,有起点和终点的字节集合,是对数据传输的总成或抽象。即数据在两设备之间的传输...
    布鲁斯不吐丝阅读 10,015评论 2 95
  • 1 IONo18 1.1IO框架 【 IO:Input Output 在程序运行的过程中,可能需要对一些设备进...
    征程_Journey阅读 948评论 0 1
  • 设计是个比较抽象,比较感性的东西,没有一个明确的评判标准,通常是仁者见仁,智者见智,在与UI设计师斗智斗勇的过程中...
    慕白_简阅读 250评论 2 1
  • 自从有了高压锅,做饭快捷方便。但是很少喝小米粥,孩子不喜欢吃,我也觉得没有电饭锅熬出来的香。 今天心血来潮,...
    今夕何夕_2e15阅读 172评论 0 0