码迷,mamicode.com
首页 > 编程语言 > 详细

Java IO

时间:2015-10-19 07:02:43      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:

对于我一个Java小白在经历过无数次鄙视之后,痛定思痛决定好好学好Java。就从Java 的 IO 开始学起吧。

可是Java 的 IO真的很烦,如图。看到这样的继承关系,大部分初学者实在不知道从何学起。那就从最原始的部分开始试试。

 

技术分享

第一个问题:什么是IO?

IO就是“外部世界”。

函数式编程会把IO的概念和程序的逻辑运算本身严格的区分开来。函数式语言里把含有IO的函数称为“非纯函数”。而完全没有IO,只是纯粹的运算的函数称为“纯函数”。纯函数的好处这里暂且按下不表。但是这种区分给了IO一个很宽泛却很全面的概念:IO就是纯函数与外部世界结合的途径。可以是从本地文件、网络socket、别的进程、外围设备、终端等等的地方读取数据的方式。数据一旦被读取,可能会被进一步加工,可能会被变换、映射、筛选,但是这些操作都不是IO,而是纯函数的操作。如果有一个信息总量的概念在IO里面,那么在发生IO的时候也就是产生信息的时候,后续的纯函数的操作都不能够增加信息的总量,当然,可以使数据变得更有序、更精练,这些是数据熵减小。

 

第二个问题:计算机世界的数据长什么样子?

0110110000110100011001111010011010100110101100101001111101100110100101011101001000010011110010101010100001100101010010100011000100100011

数据对计算机而言就长成这样子,一堆0和1的序列。当然,这一堆序列并不是数据本身,数据是一堆0和1的序列和解释这个序列的规则:

                                 数据 =  数据编码 + 解码规则 

我们的文本编辑器就是最常见的编码和解码器:我们在文本编辑器里面输入句子,点击保存,文本编辑器就把相应的句子编码成一大串01保存在硬盘,一旦我们打开这个文件,编辑器又把它解码成我们可读的文字。当然,有时候数据并不需要被解码,比如把一个文件拷贝到另一个地方,这个过程中的IO并不需要被解码,拷贝的程序简单起见就可以把一堆0和1直接输送到另一个地方去。此外,编码和解码少数情况下也可以由上层应用程序来实现。不过,Java这么强大,大部分常用的解码工作当然是有相应的IO对象来处理的。 

 

第三个问题:Java怎么读数据?

0110110000110100011001111010011010100110101100101001111101100110100101011101001000010011110010101010100001100101010010100011000100100011

上面说计算机这样看待数据,其实也不全对。因为计算机可没耐心一个bit一个bit的读取数据,在计算机世界里,最小的操作单位是一个byte,就是由8个bit位组成的数据结构。所以,计算机其实是这样看待数据的:

01101100 00110100 01100111 10100110 10100110 10110010 10011110 10110011 01001010 11101001 00001001 11100101 01010100 00110010 10100101 

Byte是计算机世界里最小的可操作对象,可以说计算机的编码是在byte上构建起的一系列更高抽象的数据结构。所谓的Java的强大的IO,就是对这些底层到更高抽象层的数据的编码和解码支持。

1,Byte

在java里,跟byte相关的数据一般称为stream,这是最小的可操作单元。Java里有InputStream和OutStream这两个抽象基类,其它的stream的类都继承自这两个基类。根据stream的源和汇的不同,可以分为FileInputStream(FileOutputStream)、ByteArrayInputStream(ByteArrayOutputStream)、PipedInputStream(PipedOutputStream)等等子类。这里用最常见的FileInputStream和FileOutputStream举例。

import java.io.*;

public class ShowByte {
    public static void main(String[] args) throws IOException {

        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream("input.txt");
            out = new FileOutputStream("output.txt");
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
                System.out.print(c); 
System.out.print(" "); } } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }

  如果"input.txt"里面是 "a中" 这两个中英文字符的话,那么结果很可能是:

97 228 184 173 10 

  很显然:97对应的是‘a‘;"228 184 173"则是中文字“中”的UTF-8编码,可以看出它占了3个字节;10则是换行符。从这里可以看出,FileInputStream根本不管编码的具体意义,它做的只是最底层的将文件的每个字节依次读出来而已。至于对信息本身的解码,要么留给上层的程序,要么更常见的,用上层的Java对象进行包装。

 

2,Char

这里的char就已经可以看做是byte的进一步抽象,因为这里的char已经不再是没有意义的01组合,这里的char代表一个字符,人类文字的最小单元。而且,在Java里面char非常简单,它一定是两个字节的大小。因为在Java里所有的字符都是通过Unicode的编码方式,Unicode统一用两个字节编码字符。咦?那为什么刚刚那个例子里面‘中’有三个byte?那是因为文本编辑器存储在硬盘上的数据大都采用UTF-8的格式,这是一种可变字节的编码方式,对于英文字符它就是一个字节的ascii码,所以非常节省存储空间。然而同时,很多中文字符也被编码成2-4个不等的字节大小。

好了,那Java怎么读取Char呢?很显然,char是byte的进一步抽象,我们只要在上面的程序上再加一层wrapper(亦或者称为filter): InputStreamReader (OutputStreamWriter)。在java里,只要看到‘reader‘和‘writer‘之类的字眼就都是用来处理char的。这里的Reader是构建在FileInputStream之上的,闲话少说,直接上代码:

import java.io.*;

public class ShowChar {
    public static void main(String[] args) throws IOException {

        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream("input.txt");
            out = new FileOutputStream("output.txt");
            InputStreamReader charStreamInput = new InputStreamReader(in);
            OutputStreamWriter charStreamOutput = new OutputStreamWriter(out);
            int c;
            
            while ((c = charStreamInput.read()) != -1) {
            	charStreamOutput.write(c);
                System.out.print(c); 
                System.out.print(" ");
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

  可以看出这段程序只是在原来的基础上增加了InputStreamReader,但是同样的输入“a中”,结果就会有一点不一样:

97 20013 10 

  ‘中’的字符变成了“20013”,而第一个程序是三个字节的“228 184 173”。什么鬼?也没啥,InputStreamReader保证是一个一个char来读的,‘中’字的unicode就是两个字节的“20013”。可是我刚刚不是说这个文件是以UTF-8编码的,读入两个字节难道不应该是“228 184” 的整数形式“58552”吗?(这里还要考虑什么Big-Endian,Small-Endian之类的编码区别),然后还有两个多余的“173”?哈哈,Java当然不会这么蠢让程序员去考虑这些细节的问题。在使用InputStreamReader之后,这个对象已经考虑了从UFT-8到Unicode之间的转换,保证每读到一个字符就一定是两个字节的Unicode的字符。也就是说,它很聪明的知道了文件是UTF-8格式的,然后知道“228 184 173”实际上就是一个字符,然后把这个字符转成了Unicode的形式,然后打出来。

 

读取字符这样的工作经常要用到,当然应该有一个更好用的对象来封装这两个底层的对象。当然有:FileReader是也!

FileReader就直接把读取和转化放在一件事里面做到了,使得这样的操作就更令人愉快了。代码变成:

import java.io.*;

public class ShowChar {
    public static void main(String[] args) throws IOException {

        FileReader in = null;
        FileWriter out = null;
        try {
            in = new FileReader("input.txt");
            out = new FileWriter("output.txt");
            int c;
            
            while ((c = in.read()) != -1) {
            	out.write(c);
                System.out.print(c); 
                System.out.print(" ");
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

  这下简单一点了,对吧?

 

 

 

.............

后面不想写了,因为发现有个博客已经写的很好了,我就姑且写到这吧。

http://blog.csdn.net/yczz/article/details/38761237 

 

 

 

 

Java IO

标签:

原文地址:http://www.cnblogs.com/renruyi/p/4888525.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!