Java字节流与字符流

字节流与字符流

流的概念

        在Java.io包中,File类是唯一一个与文件本身有关的程序处理类,但是File只能操作文件的本身,而不能操作文件的内容。在实际开发中,IO操作的核心意义在于:输入与输出操作。
        对于流的处理形式,在java.io包中提供有两类支持:

字节处理流:OutputStream(输出字节流)、InputStream(输入字节流);
字符处理流:Writer(输出字符流)、Reader(输入字符流);


        所有的流操作都应该采用如下统一的步骤进行(下面以文件处理的流程为例):

1、如果现在进行的是文件的读写操作,则一定要通过File类找到一个文件路径;
2、通过字节流或字符流的子类为父类对象实例化(都是抽象类,所以要用子类);
3、利用字节流或字符流中的方法实现数据的输入与输出操作;
4、流的操作属于资源操作,资源操作必须进行关闭处理。

OutputStream字节输出流

        首先看一下OutputStream的定义

public abstract class OutputStream extends Object implements Closeable,Flushable

        不难发现,OutputStream实现了Closeable和Flushable两个接口

public interface Closeable extends AutoCloseable {
	public void close() throws IOException;
}
public interface Flushable { 
	public void flush() throws IOException;
}


        OutputStream类定义的是一个公共的输出操作标准,而在这个操作标准中定义了三个内容输出的方法:

方法定义
输出单个字节数据:public abstract void write(int b) throws IOException;
输出一组字节数据:public void write(byte[] b) throws IOException;
输出部分字节数据:public void write(byte[] b,int off,int len) throws IOException;

        需要注意的是:OutputStream类是一个抽象类,抽象类要想获得实例化对象,应该通过子类实例的向上转型完成。
        如果现在要进行文件处理操作,则可以使用FileOutputStream子类:

  • 因为最终需要发生向上转型的处理关系,所以对于此时的FileOutputStream子类核心的关注点应该是其构造方法:
    方法定义
    【覆盖】构造方法:public FileOutputStream(File file) throws FileNotFoundException;
    【追加】构造方法:public FileOutputStream(File file,boolean append) throws FileNotFoundException;
  • 追加中的换行:\r\n

InputStream字节输入流

        与OutputStream类对应的是字节输入流,InputStream类主要实现的就是字节数据读取,定义如下:

public abstract class InputStream extends Object implements Closable


        在InputStream类中定义有如下的核心方法:

方法定义
读取单个字节数据(如果读取到底,返回-1):public abstract int read() throws IOException;
读取一组字节数据(返回的是读取的个数,没有数据返回-1):public int read(byte[] b) throws IOException;
读取一组字节数据的部分:public int read(byte[] b,int off,int len) throws IOException;

        InputStream同样属于抽象类,依靠子类类实例化对象,如果要从文件读取一定要使用FileInputStream子类,其构造方法为:public FileInputStream(File file) throws FileNotFoundException;
        对于字节输入流最麻烦的问题在于,使用read()方法读取的时候,只能够以字节数组为主进行接收。
        从JDK1.9开始,在InputStream类中增加了一个新的方法:public byte[] readAllBytes() throws IOException;(读取全部数据,该方法不建议使用)

Writer字符输出流

        使用OutputStream字节流输出进行数据输出的时候使用的都是字节类型的数据,而很多情况下,字符串的输出比较方便,所以java.io包于JDK1.1时提供了字符输出流:Writer。

public abstract class Writer extends Object implements Appendable,Closeable,Flushable


        Writer类中提供的一些输出方法:

方法定义
输出字符数组:public void write(char[] cbuf) throws IOException;
输出字符串:public void write(String str) throws IOException;

        使用Writer输出的最大优势是在于可以直接利用字符串完成,而作为字符处理的优势在于中文数据上。

Reader字符输入流

        Reader是实现字符输入流的一种类型,其本身属于一个抽象类,定义如下:

public abstract class Reader extends Object implements Readable,Closeable


        Reader类中并没有像Writer类一样提供有整个字符串的输入的处操作,只能使用字符数组实现接收。

方法定义
接收数据:public int read(char[] cbuf) throws IOException;

        字符流读取的时候只能按照数组的形式来实现操作。

字节流与字符流的区别

        在使用OutputStream和Writer输出的时候,都调用了close()方法进行了关闭处理。
        但如果在使用OutputStream输出的时候没有使用close()方法关闭输出流,会发现内容依然可以实现正常的输出,但是如果在使用Writer的时候,没有使用close()方法关闭输出流,则内容将无法进行输出,因为Writer使用了缓冲区,当使用close()方法的时候,实际上会出现强制刷新缓冲区的情况,所以这个时候,会将内容进行输出,如果没有关闭,则无法进行输出操作,所以在不关闭的情况下,想要全部输出,可以使用flush()方法强制清空。
        字节流在进行处理的时候并不会使用到缓冲区,而字符流会使用到缓冲区。另外使用缓存区的字符流更加适合于进行中文数据的处理。
6、转换流

转换流

        转换流可以实现字节流和字符流操作的功能转换,为此,在java.io包中提供有两个类:OutputsTreamWriter、InputStreamReader。

定义构造
OutputsTreamWriter:public class OutputsTreamWriter extends Writer;public OutputStreamWriter(OutputStream out);
InputStreamReader:public class InputStreamReader extends Reader;public InputStreamReader(InputStream in);


        通过类的继承结构于构造方法可以发现,所谓的转换处理,就是将接收到的字节流对象通过向上转型变成字符流对象。
        对于OutputStream类有FileOutputStream直接子类,InputStream类有FileInputStream直接子类,但是对于FileWriter、FileReader类的继承关系。

定义
FileWriter:public class FileWrtier extends OutputStreamWriter
FileReader:public class FileReader extends InputStreamReader


        实际上的缓存区可以理解为程序中间的一道缓冲区。

        文件拷贝,从JDK1.9开始InputStream和Reader类都追加又数据转存的方法:

方法
InputStream:public long transferTo(OutputStream out) throws IOException;
Reader:public long transferTo(Writer out) throws IOException;

IO流操作深入

字符编码

        在实际开发中常用的编码:

GBK/GB2312:国标编码,可以描述中文信息,其中GB2312只描述简体中文,而GBK包含有简体中文与繁体中文;
ISO8859-1:国际通用编码,可以用于描述所有字母信息,如果是象形文字则需要进行编码处理;
UNICODE编码:采用十六进制的方式存储,可以描述所有的文字信息;
UTF编码:象形文字部分使用十六进制编码,而普通的字母采用的是ISO8859-1编码,其优势在于适合快速传输,节约带宽,首选编码,主要使用“UTF-8”编码。
方法定义
列出本机属性:System.getProperties().list(System.out);

内存操作流

        文件操作流的特点,程序利用InputStream读取文件内容,再利用OutputStream向文件输出内容。所有操作都是以文件为终端的。

        如果此时需要实现IO操作,但是又不希望产生文件,则就可以以内存为终端进行处理。

        在Java中提供有两类内存操作流:

字节内存操作流:ByteArrayOutputStream、ByteArrayInputStream;
字符内存操作流:charArrayWriter、charArrayReader;
构造方法
ByteArrayInputStream:public ByteArrayInputStream(byte[] buf);
ByteArrayOutputStream:public ByteArrayOutputStream();

        在ByteArrayOutputStream类中提供了一个可以获取全部保存在内存流中的数据信息的方法:

方法定义
获取数据:public byte[] toByteArray();
使用字符串的形式来获取:public String toString();

管道流

        管道流主要的功能是实现两个线程之间的IO处理操作。

        对于管道流也是分为两类:

字节管道流:PipedOutputStream、PipedInputStream;
方法定义
连接处理:public void connect(PipedInputStream snk) throws IOException;
字符管道流:PipedWriter、PipedReader;
方法定义
连接处理:public void connect(PipedReader snk) throws IOException;

        (管道流是OutputStream等的子类,即继承结构图同上,与FileInputStream、ByteArrayInputStream等同级,图略)

RandomAccessFile

        对于文件内容的操作主要是通过InputStream(Reader)、OutputStream(Writer)来实现,但是利用这些类实现的内容读取只能将数据部分部分读取进来。当文件过大时,如果仍然采用传统的IO操作进行读取和分析根本不可能完成。所以在java.io包中提供了RandomAccessFile类,该类可以实现文件的跳跃式读取,可以只读取文件的部分内容(前提:需要有一个完善的保存形式,即数据保存的位数要确定好)。

        RandomAccessFile类中定义有如下操作:

方法定义
构造方法:public RandomAccessFile(File file,String mode) throws FileNotFoundException;
  • 文件处理模式:r、rw;

        RandomAccessFile最大的特点在于数据的读取处理上,因为所有的数据是按照固定的长度进行保存,所以读取的时候进行跳字节读取:

方法定义
跳字节读取(向下跳):public int skipBytes(int n) throws IOException;
跳字节读取(向上跳):public void seek(long pos) throws IOException;

        整体的使用之中,由用户自行定义要读取的位置,而后按照指定的结构进行数据的读取。

输入与输出支持

打印流

        程序实现内容的输出,核心本质一定要依靠OutputStream类完成,但是OutputStream最大的缺点在于这个类的数据输出操作功能有限:public void write(byte[] b) throws IOException,所有的数据一定要转为字节数组后才可以输出,如果要输出long、double、Date等,必须将数据转为字节的形式才能处理,过于麻烦。
        所以在java.io包中提供有了打印流:PrintStream、PrintWriter。

定义构造方法
PrintStream:public class PrintStream extends FilterOutputStream implements Appendable,Closeablepublic PrintStream(OutputStream out);
PrintWriter:public class PrintWriter extends Writerpublic PrintWriter(Writer out);public PrintWriter(OutputStream out);


        比起直接使用OutputStream类,使用PrintStream、PrintWriter类处理的操作会更加简单,内容输出首先考虑打印流。

System类对IO的支持

        System类是一个从头到尾一直在使用的系统类,该类中提供有三个与输入输出有关的常量:

方法定义
标准输出(显示器):public static final PrintStream out;
错误输出:public static final PrintStream err;
标准输入(键盘):public static final InputStream in;

        System.out和System.err都是同一类型的,但是使用不同的编译软件,软件会对两种进行颜色区分(System.err在Eclipse中输出时颜色为红色)。
        最初的设计目的:System.out是输出希望用户可以看到的,而System.err是输出用户不可见的。如果需要也可以修改输出的位置:

方法定义
修改out的输出位置:public static void setOut(PrintStream out);
修改err的输出位置:public static void setErr(PrintStream err);

        在System类中还提供有in的常量,该常量对应的是标准输入设备键盘的输入处理,可以实现键盘的数据输入。但是这样的输入本身是有缺陷的:如果长度不足,就只能接收部分数据,输入可能需要进行重复的输入流数据接收,而且接收的时候还可能牵扯到中文输入,可能出现乱码问题。

BufferedReader缓冲输入流

        BufferedReader类提供的是一个缓冲字符输入流的概念,利用该类可以很好解决输入流数据读取的问题。该类是在最初的时候提供的最完善的数据输入处理(JDK1.5之前),该类提供有一个重要方法:

方法定义
读取一行数据:public String readLine() throws IOException;

Scanner扫描流

        java.uitl.Scanner是从JDK1.5之后追加的一个程序类,其主要目的是为了解决输入流的访问问题,可以理解为BufferedReader的替代功能类。在Scanner类中有以下几种方法:

方法定义
构造方法:public Scanner(InputStream source);
判断是否有数据:public boolean hasNext();
取出数据:public String next();
设置分隔符:public Scanner useDelimiter(String pattern);

        使用Scanner输入数据还有一个最大的特点是可以直接利用正则进行验证判断。

  • hasNext()中可以直接添加正则表达式进行判断,next()中同样可以。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值