Java Io 操作解析(1)– 热爱改变生活
我的GitHub GitHub |     登录
  • If you can't fly, then run; if you can't run, then walk; if you can't walk, then crawl
  • but whatever you do, you have to keep moving forward。
  • “你骗得了我有什么用,这是你自己的人生”
  • 曾有伤心之地,入梦如听 此歌

Java Io 操作解析(1)

Java sinvader 3081℃ 0评论

什么是 IO

I/O 输入/输出 (Input/Output), 分为 IO 设备和 IO 接口两个部分。 在 POSIX 兼容的系统上,例如 Linux 系统,I/O 操作可以有多种方式,比如 DIO(Direct I/O),AIO(Asynchronous I/O 异步 I/O),Memory-Mapped I/O(内存映设 I/O) 等,不同的 I/O 方式有不同的实现 方式和性能,在不同的应用中可以按情况选择不同的 I/O 方式。

(以上来自百度百科

In computing, input/output or I/O (or, informally, io or IO) is the communication between an information processing system, such as a computer, and the outside world, possibly a human or another information processing system. Inputs are the signals or data received by the system and outputs are the signals or data sent from it. The term can also be used as part of an action; to “perform I/O” is to perform an input or output operation. I/O devices are used by a human (or other system) to communicate with a computer. For instance, a keyboard or mouse is an input device for a computer, while monitors and printers are output devices. Devices for communication between computers, such as modems and network cards, typically perform both input and output operations.
在计算机的运行中,input/output 或者简称 I/O 是在信息处理系统中的一种沟通方式,比如说一台电脑或者外部世界,又或者一个人、其他的信息处理系统。输入 (Input) 是这个系统接收到的信号或者数据,输出是这个信息处理系统向外界发送出来的信号或者数据。IO 这个术语同样可以用于一个动作的一部分, 运行 I/O 可能是运行输入或者是输出操作。人们或者其他的系统使用 I/O 设备来和电脑进行交互。比如,键盘或者鼠标就是一种为电脑设计的输入设备,而显示器以及打印机就是输出的设备。比如说调制解调器以及网卡设备,就被用来和电脑进行交互,并同时兼有输入输出功能。
Note that the designation of a device as either input or output depends on perspective. Mice and keyboards take physical movements that the human user outputs and convert them into input signals that a computer can understand; the output from these devices is the computer’s input. Similarly, printers and monitors take signals that a computer outputs as input, and they convert these signals into a representation that human users can understand. From the human user’s perspective, the process of reading or seeing these representations is receiving input; this type of interaction between computers and humans is studied in the field of human–computer interaction.
要知道设备输入输出的定制在于到底持什么观点。人们用物理动作的方式使用鼠标和键盘来进行输出然后将它们转化为电脑的能理解的输入信号,这些设备输出的信息也就是电脑的输入。类似的,打印机和屏幕监视器获得电脑的输出信号来作为自己的输入信号,然后它们将这些信号进行转换并且以人们能以理解的样子呈现。以一个人类用户的观点来看,读或者看这些(输出或者陈述)就是在接受 input,这种类型的人类和计算机之间的互动是一种在人机交互领域的研究。

(以上来自维基百科)

Java 中的 IO

“对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务。” ——《Think in Java》
无论是系统、还是语言的设计中 IO 的设计都是异常复杂的。面临的最大的挑战一般是如何覆盖所有可能的因素,我们不仅仅要考虑文件、控制台、网络、内存等不同的种类,而且要处理大量的不同的读取方式,如:顺序读取、随机读取,二进制读取、字符读取,按行读取、按字符读取……
Linux 是第一个将设备抽象为文件的操作系统,在 Linux 中所有的外部设备都可以用读取文件的方法读取,这样编程人员就可以以操作文件的方法操作任何设备。C++在 IO 方面也做了一些改进――引进了流的概念,我们可以通过 cin、cout 读写一些对象。Java 语言在 IO 设计方面取得较大的成功,它是完全面向对象的,主要采用装饰器模式避免大量的类,包括了最大的可能性,提供了较好的扩展机制……
Java 库的设计者通过创建大量类来攻克这个难题。事实上,Java 的 IO 系统采用了如此多的类,以致刚开始会产生不知从何处入手的感觉(具有讽刺意味的是,Java 的 IO 设计初衷实际要求避免过多的类)。” 上面一段来自《Think in Java》,确实很多初学者刚刚学习 java 的 IO 时会比较茫然,不过等我们知道装饰器模式(Decorator)的用意、场景及其在 Java 的 IO 包中的使用,你可能会真正领会整个 IO 的 FrameWork。

下面,将根据 Thinking in Java 中的讲解过程来继续研究。

1.File 类

File 类是 java.io.File 包下的一个类,从名字上来看,这个类是一个文件类,代指的是文件,然而事实上,这个类值得除了是一个文件之外,它还可能是一个文件夹。如果他是一个文件夹,那么我们可以通过 File 类下面的 list 方法获得这个文件夹下面的所有文件的名字:

private static void listFileNames(File file) {
	String[] list = file.list();
	for (int i = 0; i < list.length; i++) {
		System.out.println(list[i]);
	}
}

那么如果我只要取文件名中包含 Test 的文件,那么要怎么做?
第一种:我在上面已经获取到了所有的文件的名字,然后遍历获得的这些名字,如果名字中包含 Test,那么我再把它输出出来。

private static void listFileNames(File file) {
	String[] list = file.list();
	for (int i = 0; i < list.length; i++) {
		String name = list[i];
		if (name.contains("Test")) {
			System.out.println(name);
		}
	}
}

第二种:java 的工程师在设计的时候就帮我们在这些程序猿想到了,他们设计了一种方法,这就是 list 的一个重载方法 list(FilenameFilter filter)。
下面是 list(FilenameFilter filter) 的代码

public String[] list(FilenameFilter filter) {
        String names[] = list();
        if ((names == null) || (filter == null)) {
            return names;
        }
        //上面的代码会将目录下的文件或者目录都列出来,如果过滤项目是空,就将文件名的数组直接返回
        List v = new ArrayList<>();
        for (int i = 0 ; i < names.length ; i++) {
            //看到这里,就有了疑问,这个 filter 的 accept 方法在哪里?  现在,跳过这里,看【后面的代码】
            if (filter.accept(this, names[i])) {
               
            //看到这里,就发现,如果返回值是 true 的话,这个名字才会被加入给我们的结果中,也就是说如果这个结果是我们需要的,那么就返回 true,然后我们就能在最后的返回结果哪里获得它了,也就实现了【我们自己写的方法】的那样的结果,【返回,继续查看】
                v.add(names[i]);
            }
        }
        return v.toArray(new String[v.size()]);
 }


这里是 FilenameFilter 中的代码:

interface FilenameFilter {
    /**
     * Tests if a specified file should be included in a file list.
     *
     * @param   dir    the directory in which the file was found.
     * @param   name   the name of the file.
     * @return  true if and only if the name should be
     * included in the file list; false otherwise.
     */
    boolean accept(File dir, String name);
}

这是一个接口,从注释中我们看到,第一个参数查询的文件夹的路径,第二个是文件的路径,如果我们调用的是 list(FilenameFilter fileFilter) 方法,并传入了 fileFilter 方法,那么我们就必须覆盖父类的方法,如下:

String[] listFilters = file.list(new FilenameFilter() {
			
	@Override
	public boolean accept(File dir, String name) {
		return false;
	}
});

在 accept 方法中,我们就可以对获得的名字进行预处理了,比如我们要做的 “判断名字中是否有 Test”

String[] listFilters = file.list(new FilenameFilter() {
			
	@Override
	public boolean accept(File dir, String name) {
		if (name.contains("Test")) {
			return true;
		}
		return false;
	}
});

在 accept 中,我们什么时候返回 true,什么时候返回 false 呢?点【这里】我们去看这个返回的值是怎么被使用的。

File 类部分方法使用

File file = new File("src\\cn\\sumile\\2.txt");
		fileData(file);
		System.out.println();
		File file2 = new File("src\\cn\\sumile");
		fileData(file2);
		System.out.println();
		File file3 = new File("src\\cn\\sumile\\MainClass2.java");
		// 是否是可执行
		System.out.println(file.canExecute());
		// 对比两个文件(对比的是路径)
		System.out.println(file2.compareTo(file3));
		try {
			// 创建文件
			System.out.println(file3.createNewFile());
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 删除文件
		// System.out.println("文件" + file3.getAbsolutePath() + "删除:" +
		// file3.delete());
		// 磁盘剩余空间
		System.out.println("磁盘剩余空间:" + file.getFreeSpace() / 1024 / 1024 / 1024 + "G");
		System.out.println("磁盘总空间:" + file.getTotalSpace() / 1024 / 1024 / 1024 + "G");
		System.out.println("磁盘可用空间:" + file.getUsableSpace() / 1024 / 1024 / 1024 + "G");
		System.out.println("文件修改名称:" + file.renameTo(new File("src\\cn\\sumile\\1.txt")));

API 参考

2. 输入和输出

首先来看一下在《Thinking in Java》书中对 InputStream 类型的介绍:

功能

构造器参数

如何使用

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

功能

构造器参数

如何使用

ByteArrayOutputStream 在内存中穿件缓冲区,所有送往 “流” 的数据都要防止在此缓冲区 缓冲区初始化尺寸(可选的)用于指定数据的目的地,将其与 FilterOutputStrem 对象相连以提供有用的接口
FileOutputStream 用于将信息写至文件 字符串,表示文件名、文件或 FileDescriptor 对象指定数据的目的地,将其与 FilterOutputStream 对象相连以提供有用的接口
PipedOutputStream 任何写入其中的信息都会自动作为相关 PipedInputStream 的输出。实现 “管道化” 的概念 PipedInputStream 指定用于多线程的数据的目的地,将其与 FilterOutputStream 对象相连以提供有用接口
FilterOutputStream 抽象类,作为” 装饰器” 的接口。其中,“装饰器” 为其他 OutputStream 提供有用功能
¥ 有帮助么?打赏一下~

转载请注明:热爱改变生活.cn » Java Io 操作解析(1)


本博客只要没有注明“转”,那么均为原创。 转载请注明链接:sumile.cn » Java Io 操作解析(1)

喜欢 (0)
发表我的评论
取消评论
表情

如需邮件形式接收回复,请注册登录

Hi,你需要填写昵称和邮箱~

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址