8、回推流:PushbackInputStream与PushbackReader

PushbackInputStream/PushbackReader 用于解析InputStream/Reader内的数据,允许你读取字节/字符后,回推(pushback)到流中,而不破坏流。

PushbackInputStream类具有以下构造函数:

PushbackInputStream(InputStream inputStream)
PushbackInputStream(InputStream inputStream,int numBytes)

第一种形式创建的流对象允许将一个字节返回到输入流; 第二种形式创建的流对象具有一个长度为numBytes的回推缓存,从而允许将多个字节回推到输入流中。

提供了unread()方法,如下所示:

void unread(int b)
void unread(byte[] buffer)
void unread(byte[] buffer,int offset,int numBytes)

第一种形式回推b的低字节,这会使得后续的read()调用会把这个字节再次读取出来。第二种形式回推buffer中的字节。第三种形式回推buffer中从offset开始的numBytes个字节。当回推缓存已满时,如果试图回推字节,就会抛出IOException异常。

示例:

public static void main(String[] args) throws IOException {String filepath = "file.bin";java.io.OutputStream os = null;try {os = new FileOutputStream(filepath);os.write('#');os.write(new byte[]{'a', 'b', 'c', 'd'});os.flush();// 把缓冲区内的数据刷新到磁盘} finally {if (os != null) {os.close();// 关闭流}}/*** 回推(pushback)*/PushbackInputStream pis = null;try {//pis = new PushbackInputStream(new FileInputStream(filepath));pis = new PushbackInputStream(new FileInputStream(filepath), 3);int len = -1;byte[] bytes = new byte[2];while ((len = pis.read(bytes)) != -1) {if ('b' == bytes[0]) {//pis.unread('U');//pis.unread(bytes);pis.unread(new byte[]{'1', '2', '3'});}for (int i = 0; i < len; i++) {System.out.print(((char) bytes[i]));}}System.out.println();} finally {if (pis != null)pis.close();}/*** 会发现PushbackInputStream并没有改变目标介质的数据,不破坏流*/try {pis = new PushbackInputStream(new FileInputStream(filepath));int len = -1;byte[] bytes = new byte[2];while ((len = pis.read(bytes)) != -1) {for (int i = 0; i < len; i++) {System.out.print(((char) bytes[i]));}}} finally {if (pis != null)pis.close();}}

注:PushbackInputStream对象会使得InputStream对象(用于创建PushbackInputStream对象)的mark()或reset()方法无效。对于准备使用mark()或reset()方法的任何流来说,都应当使用markSupported()方法进行检查。

9、行数记录:LineNumberInputStream与LineNumberReader

LineNumberInputStream与LineNumberReader提供跟踪行号的附加功能。行是以回车符 ('\r')、换行符 ('\n') 或回车符后面紧跟换行符结尾的字节序列。在所有这三种情况下,都以单个换行符形式返回行终止字符。 行号以 0 开头,并在 read 返回换行符时递增 1。

使用getLineNumber()可以获取当前读取所在行数。

示例:

public static void main(String[] args) throws IOException {String filepath = "file.txt";java.io.Writer w = null;try {w = new FileWriter(filepath);w.write("百世山河任凋换,一生意气未改迁。愿从劫火投身去,重自寒灰飞赤鸾。\r\n");w.write("沧海桑田新几度,月明还照旧容颜。琴心剑魄今何在,留见星虹贯九天。 \n");w.write("冰轮腾转下西楼,永夜初晗凝碧天。长路寻仙三山外,道心自在红尘间。 \n");w.write("何来慧剑破心茧,再把貂裘换酒钱。回望天涯携手处,踏歌重访白云间。\n");w.write("何以飘零去,何以少团栾,何以别离久,何以不得安? \n");w.flush();// 把缓冲区内的数据刷新到磁盘} finally {if (w != null) {w.close();// 关闭流}}/*** LineNumberReader*/LineNumberReader lnr = null;try {lnr = new LineNumberReader(new FileReader(filepath));int len = -1;char[] chars = new char[2];//int lastLineNumber = -1;while ((len = lnr.read(chars)) != -1) {for (int i = 0; i < len; i++) {System.out.print(((char) chars[i]));}/*int lineNumber = lnr.getLineNumber();if (lineNumber != lastLineNumber) {System.out.println("---------------行数:" + lineNumber);lastLineNumber = lineNumber;}*/}int lineNumber = lnr.getLineNumber();System.out.println("行数:" + lineNumber);System.out.println();} finally {if (lnr != null)lnr.close();}}

10、StreamTokenizer的使用

StreamTokenizer定义了几种基本的常量用于标识解析过程:TT_EOF(流结尾)、TT_EOL(行结尾)、TT_NUMBER(数字符号, 0 1 2 3 4 5 6 7 8 9 . -都属于数字语法)、TT_WORD(一个单词)。
ttype 在调用 nextToken 方法之后,此字段将包含刚读取的标记的类型。
nval 如果当前标记是一个数字,则此字段将包含该数字的值。
sval 如果当前标记是一个文字标记,则此字段包含一个给出该文字标记的字符的字符串。

public static void main(String[] args) throws IOException {StreamTokenizer tokenizer = new StreamTokenizer(new StringReader("Sven had 7 shining ring..."));while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {// 流末尾if (tokenizer.ttype == StreamTokenizer.TT_WORD) {System.out.println(tokenizer.sval);} else if (tokenizer.ttype == StreamTokenizer.TT_NUMBER) {System.out.println(tokenizer.nval);} else if (tokenizer.ttype == StreamTokenizer.TT_EOL) {// 行末尾System.out.println();}}//System.out.println(tokenizer.lineno());
}

基本方法介绍一下:

 nextToken()  - 从此标记生成器的输入流中解析下一个标记。

(1)标记注释

commenChar(int ch) - 指定某个字符为注释字符,此字符之后直到行结尾都被stream tokenizer忽略。

slashSlashComments(boolean flag) - 如果为true,则/*与*/之间的都被认为是注释,反之,不是。

slashStartComments(boolean flag) - 如果为true,则//之后到行结尾的所有都被认为是注释,反之,不是。

(2)基本语义

eolIsSignificant(boolean flag) - 决定一个行结束符是否被当作一个基本的符号处理,如果是true,则被当作一个基本符号,不当作普通的分隔符,如果是false,则保持原义,即当作普通的分隔符。

lowerCaseMode(boolean flag) - 决定是否读取一个单词时是否转变成小写。

parseNumbers() - 当stream tokenizer遭遇到一个单词为双精度的浮点数时,会把它当作一个数字,而不是一个单词。

resetSyntax() - 重置语法表使所有的字符都被认为是“ordinary”。

(3)指定字符语义

ordinaryChar(int ch) - 指定字符在这个tokenizer中保持原义,即只会把当前字符认为普通的字符,不会有其他的语义。
ordinaryChars(int low, int hi) - 指定范围内的字符保持语义,同上

whitespaceChars(int low, int hi) - 字符low与hi之间的所有字符都被当作为空格符,即被认识为tokenzier的分隔符。
wordChars(int low, int hi) - 字符low与hi之间的所有字符都被当作为单词的要素。一个单词是由一个单词要素后面跟着0个或者更多个单词要素或者数字要素。

11、合并流SequenceInputStream

SequenceInputStream会将与之相连接的流集组合成一个输入流并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的末尾为止。 合并流的作用是将多个源合并合一个源。

public static void main(String[] args) throws IOException {String filepath1 = "file1.txt";String filepath2 = "file2.txt";java.io.Writer w = null;try {w = new FileWriter(filepath1);w.write("百世山河任凋换,一生意气未改迁。愿从劫火投身去,重自寒灰飞赤鸾。\r\n");w.write("沧海桑田新几度,月明还照旧容颜。琴心剑魄今何在,留见星虹贯九天。 \n");w.write("冰轮腾转下西楼,永夜初晗凝碧天。长路寻仙三山外,道心自在红尘间。 \n");w.write("何来慧剑破心茧,再把貂裘换酒钱。回望天涯携手处,踏歌重访白云间。\n");w.flush();// 把缓冲区内的数据刷新到磁盘} finally {if (w != null) {w.close();// 关闭流}}try {w = new FileWriter(filepath2);w.write("何以飘零去,何以少团栾,何以别离久,何以不得安? ");w.flush();// 把缓冲区内的数据刷新到磁盘} finally {if (w != null) {w.close();// 关闭流}}java.io.Reader r = null;try {Vector<InputStream> v = new Vector<InputStream>(2);InputStream s1 = new FileInputStream(filepath1);InputStream s2 = new FileInputStream(filepath2);v.addElement(s1);v.addElement(s2);r = new BufferedReader(new InputStreamReader(new SequenceInputStream(v.elements())));char[] data = new char[256];int len = -1;while ((len = r.read(data)) != -1) {// -1 表示读取到达文件结尾//操作数据for (int i = 0; i < len; i++) {System.out.print(data[i]);}}} finally {if (r != null) {r.close();// 关闭流}}}

更多Demo:https://git.oschina.net/svenaugustus/MyJavaIOLab

本文只针对标准IO的知识总结,其他IO总结姊妹篇(NIO)请参见:
+ JavaNIO编程一览笔录: https://my.oschina.net/langxSpirit/blog/899954

转载于:https://www.cnblogs.com/aoshicangqiong/p/8035189.html

Java 标准 IO 流编程一览笔录( 下 )相关推荐

  1. 【Java网络编程与IO流】Java中IO流分为几种?字符流、字节流、缓冲流、输入流、输出流、节点流、处理流

    Java网络编程与IO流目录: [Java网络编程与IO流]Java中IO流分为几种?字符流.字节流.缓冲流.输入流.输出流.节点流.处理流 [Java网络编程与IO流]计算机网络常见面试题高频核心考 ...

  2. Java的IO流与网络编程

    目录 一.概述 二.文件类(File) 1. File类的构造.获取属性 2. File类获取子文件或目录 3. File类文件重命名 4. File类的判断功能 5. File类创建.删除功能 三. ...

  3. Java io流---拷贝文件夹下的所有文件和目录

    Java io流-拷贝文件夹下的所有文件和目录 代码: package demo01;import java.io.*; import java.util.TreeMap;public class C ...

  4. java基础 io流 字节流 字符流 节点流 包装流 转换流 缓冲流 对象流 打印流 Properties类

    目录 1.概念 2.常用的文件操作 2.1 创建文件 2.2 获取文件相关信息 2.3 目录的操作和文件删除 3. IO流原理及流的分类 3.1 流的分类 4.InputStream 字节输入流 4. ...

  5. Java入门——IO流

    一.File类的使用 1.1 File类的实例化 java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关 File 能新建.删除.重命名文件和目录,但File 不能访问文件内容本身. ...

  6. # Java基础——IO流

    Java基础--IO流 File类的使用(熟悉构造器和方法的使用) File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹) File类的声明在java.io包下 文件和文件目录路径的抽象表示 ...

  7. Java基础—IO流

    第一讲   IO概述 1. 流的概念 IO流即InputOutput的缩写,在Java中IO流用来处理设备之间的数据传输,Java对数据的操作是通过IO流的方式, 我们可以把IO流抽象的当作一根管道, ...

  8. Java中IO流体系

    转载: https://mp.weixin.qq.com/s?__biz=MzA5NzgzODI5NA==&mid=2454030958&idx=1&sn=df27aadb92 ...

  9. Java中IO流,输入输出流概述与总结(转载自别先生文章)

    Java中IO流,输入输出流概述与总结 总结的很粗糙,以后时间富裕了好好修改一下. 1:Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中.其中, 所有输入流类都 ...

  10. 第15章-输入/输出 --- 理解Java的IO流

    (一)理解Java的IO流 JAVA的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出(键盘.文件.网络连接等)抽象表述为"流"( ...

最新文章

  1. mysql常见报错解决办法
  2. FragmentStack
  3. Java代码的执行顺序
  4. abap常用系统变量
  5. java设计模式2-观察者模式
  6. 分离圆环图显示百分比_excel这个百分比图,你不一定会制作
  7. paip.输入法编程---词频顺序order by py
  8. TP-LINK设备如何配置无线上网短信Wifi认证?
  9. idea 设置字体大小
  10. SpringBoot使用自定义https
  11. 成语接龙快速接到“一个顶俩” (附api)
  12. python 对png图片压缩
  13. 容斥定理与鸽巢定理(抽屉定理)
  14. uIP使用例子应用(一)
  15. Java Web 开发实战经典 基础篇(1)
  16. Jenkins World 贡献者峰会及专家答疑展位
  17. 二进制数求反(C语言)
  18. Linux服务器如何做raid1,Linux下制作raid1
  19. 根据布尔表达式绘制电路
  20. java webservice实例教程

热门文章

  1. css加号图标_excel单元格加号展开折叠
  2. 精密划片机维护及保养
  3. SDUT —— 计算组合数
  4. 杂记 - 0002 - 衣服 - 尺寸表与跳码
  5. 线性代数学习笔记(七)——克莱姆法则
  6. 解决SSLHandshakeException :sun.security.validator.ValidatorException: PKIX path building failed:
  7. 风火牙疼,紧急止痛、快速治疗的真实历程
  8. 微信小助手 mac版功能
  9. 1467: 平面点排序(一)(结构体专题)
  10. 浅谈使用postman的CryptoJS.MD5加密带有中文(已进行unicode编码)以及url的字符串与md5在线加密工具加密不一致的原因,附加解决方法。