Java输入流和输出流详解

Java输入流和输出流详解

参考文献

https://docs.oracle.com/javase/tutorial/essential/io/streams.html

讲解的很详细,很容易懂。

I/O Streams

一个IO流代表一个输入源或者一个输出目的地。一个流可以代表许多不同种类的源, 也可以代表不同种类的目的地。

什么意思?
余成林:源可以是磁盘文件,设备(例如,控制台),其他程序和内存数组等。这就叫做不同类型的源。目的地也可以是磁盘文件,设备,其他程序和内存数据等,这就叫做不同类型的输出目的地。

流支持不同类型的数据,包括字节类型,基本数据类型,对象等。一些流只纯粹将数据传送过来,还有一些流可以对数据进行一些转换。

例如,BufferReader可以一行一行的读取, PrintWriter.println(data)会在data的尾部加上行终结符。

无论流的内部是如何工作的,all streams present the same simple model to programs that use them; 流是a sequence of data. A program uses an input stream to read data from a source, one item at a time.

余成林:可以把流想象成水管子,水管子可以将数据运送到目的地。输入流是从数据源流向程序,输出流是从程序流向数据源。输入和输出都是相对于程序的。

在这里插入图片描述

A program uses an output stream to write data to a destination, one item at a time.
在这里插入图片描述

所以关键的问题是我们要知道data source到底是谁!因为一方是program,另一方是data source.

流可以handle各种各样的数据,从基本类型到高级对象,流都是可以handle的。

对,从字节,到字符,到一行,流都是可以处理的,包括输出的格式,流都是可以决定的。现在不懂没事儿,往后看

知道这些还不够,还要知道字节流和字符流的概念,因为知道了字节流和字符流的概念,你才能够更好的理解reader和writer。

真的复杂!慢慢来,加油!

字节流(byte stream)

程序使用字节流来执行8-bit字节的输入和输出。所有的自己流都是继承InputStream and OutputStream

有几种字节流类, 为了演示字节流是如何工作的,我们关注文件的IO字节流。FileInputStream and FileOutputStream, 其他类型的字节流大致也是这么使用, They differ mainly in the way they are constructed.

就是创建的时候不同,所以当在创建的时候,并且感到一年懵逼的时候,会可以查看一下这个流的构造函数是怎样的,例如BufferedReader的构造函数的参数必须是Reader类型的,所以就可以使用InputStreamReader来进行转换。

使用字节流

我们将会探索FileInputStream和FileOutputSteam,

怎么探索?

举个例子, 看下面这个java程序,其中xanadu.txt是一个已经创建好的文本文件,outagain.txt也是一个文本文件,是待输出的文件名,这个文件可以提前创建,也可以不提前创建,如果提前没有创建,程序会为我们创建,然后往这个新创建的文件中写入数据。
CopyBytes.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyBytes {
    public static void main(String[] args) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream("xanadu.txt");
            out = new FileOutputStream("outagain.txt");
            int c;
            while ((c = in.read()) != -1) { // 读取的都是ASCII值,(一次读取一个字节,8bit,一个英文字母占一个字节,一个中分字符占2个字节,例如,如果xanadu.txt文件的内容是abde, 则c这个变量每次循环得到的值分别是97,98,100,101,不信的话你可以打印看一下)
                out.write(c);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

看下面这个图就好了。
在这里插入图片描述
注意,当我们不在使用一个流的时候,我们一定要关闭这个流,否则的话可能会导致严重的资源泄漏。

对,不同的时候把水龙头关上
至此,文件字节流我就讲解清楚了。

好了,那什么时候我们不使用字节流呢?

看起来,我们刚刚写的那个字节流的程序非常好用,但是非常的底层。

什么叫非常的底层?
余成林:我们直接操作的是字节

由于xanadu.txt包含的是字符数据,所以最好的方法是使用字符流。我们接下来就来讨论字符流。当然还有更多的流for more complicated data types. 字节流应该仅仅用于最基本的输入/输出。

字符流

The Java platform stores character values using Unicode conventions. 字符流IO translates this internal format to and from the local character set.

什么叫做unicode convention?
余成林:暂时不研究

在西方国家,the local character set is usually an 8-bit superset of ASCII.

对大多数应用来说,字符流IO并不比字节流IO复杂。使用流类进行的输入和输出将自动转换成本地字符集。A program that uses character streams in place of byte streams automatically adapts to the local character set and is ready for internationalization.
转化之类的东西都不用我们程序员操心。

如果国际化不是首要考虑的事情,你可以直接使用字符流类,完全不用去操心字符集的问题。如果国际化是要考虑的事情,你的程序可能需要做非常微小的调整。

问题不大

使用字符流

所有的字符流类都是继承自Reader and Writer.
与字节流一样,有一些字符流类专注于文件IO: FileReader 和 FileWriter. 下面这个CopyCharacters的例子就说明了这些类是如何使用的。

CopyCharacters.java

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyCharacters {
    public static void main(String[] args) throws IOException {
        FileReader inputStream = null;
        FileWriter outputStream = null;
        try {
            inputStream = new FileReader("xanadu.txt");
            outputStream = new FileWriter("characteroutput.txt");
            int c;
            while ((c = inputStream.read()) != -1) {
                outputStream.write(c);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

CopyCharacters和CopyBytes这两个文件很相似。
注意一点,虽然CopyBytes和CopyCharacters使用的都是int 变量来从文件中读取,但是,在CopyCharacters, the int variable holds a character value in its last 16 bits(两个字节), in CopyBytes, the int variable holds a byte value in its last 8 bits.

Character Streams that Use Byte Streams

字符流经常是字节流的wrapper。 当字符流在字符和字节之间处理转换的时候,字符流使用字节流执行具体的IO。例如,FileReader使用FileInputStream, FileWriter uses FileOutputStream.

余成林:意思就是你使用字符流的时候,你只需要关注字符,因为字节这一级别的东西是由字符流wrap的字节流类来管的,你就不用管了。

有两个专门的byte-to-character “bridge" steams: InputStreamReader和OutputStreamReader. 当某一个字节流暂时还没有已经封装好的字符流类时,使用 InputStreamReader和OutputStreamReader来创建满足我们需要的字符流。

FileReader是FileInputStream已经封装好的字符流,FileWriter是FileOutputStream已经封装好的字符流。

Line-Oriented IO

什么,说好的不是字符流,就是字节流,怎么突然来了个行级的IO,你是个什么怪?

既然有,那就有他有用的地方,来看看

字符I/O usually occurs in bigger units than single characters. 一个最普遍的单元就是一行。a string of characters with a line terminator at the end.

A line terminator can be a carriage-return/line-feed sequence("\r\n), a single carriage-return("\r") or a single line-feed("\r"). 假定所有可能的line terminators允许程序读取文本文件,created on any of widely used operating systems.

让我们来修改一下CopyCharacters这个例子,我们使用面向行的I/O. To do this,我们必须使用我们以前没有见过的两个类:

  1. BufferedReader
  2. PrintWriter

我们会在Buffered I/O和Formatting中进行深入的讲解。

你会讲解,我不一定会看呀

现在,我们只对他们对面向行的I/O感兴趣。

可以,现在我们只对你的一部分感兴趣,呵呵

CopyLines.java

import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;

public class CopyLines {
    public static void main(String[] args) throws IOException {
        BufferedReader inputStream = null;
        PrintWriter outputStream = null;
        try {
            inputStream = new BufferedReader(new FileReader("xanadu.txt"));
            outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));
            String l;
            while ((l = inputStream.readLine()) != null) {
                outputStream.println(l);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

可以,这英文的就是不一样,越看越带劲。

BufferedReader invokes readLine returns a line of text with the line. PrintWritter使用println进行输出,which appends the line terminator for the current operating system. 这个行终结符可能和输入文件的行终结符不一样。

没毛病,操作系统不一样的话,文件的终结符就不一样。

There are many ways to structure text input and output beyond characters and lines.
我下一讲就讲解这个!

想要学习更多,点击https://docs.oracle.com/javase/tutorial/essential/io/scanfor.html

OK!针对java的输入流和输出流算是彻底搞懂了!至少在入门阶段是正本清源。

猜你喜欢

转载自blog.csdn.net/ChenglinBen/article/details/91127877
今日推荐