Java 标准 IO 流编程一览笔录( 下 )
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
Java 标准 IO 流编程一览笔录( 下 )的更多相关文章
- Java 标准 IO 流编程一览笔录( 上 )
Java标准I/O知识体系图: 1.I/O是什么? I/O 是Input/Output(输入.输出)的简称,输入流可以理解为向内存输入,输出流是从内存输出. 2.流 流是一个连续的数据流,可以从流中读 ...
- Java标准I/O流编程一览笔录
I/O是什么 I/O 是Input/Output(输入.输出)的简称,输入流可以理解为向内存输入,输出流是从内存输出. 流 流是一个连续的数据流,可以从流中读取数据,也可以往流中写数据.流与数据源,或 ...
- [JAVA]标准IO流操作
import java.io.*; /** * @Description: * @projectName:JavaTest * @see:PACKAGE_NAME * @author:郑晓龙 * @c ...
- Java之IO流学习总结【下】
2.字节流 |-- InputStream(读) |-- OutputStream(写) 由于字节是二进制数据,所以字节流可以操作任何类型的数据,值得注意的是字符流使用的是字符数组char[]而字节流 ...
- Java 多线程并发编程一览笔录
Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...
- Java之IO流用法总结
Java的IO流概述:1.I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输.如读/写文件,网络通讯等.2.Java程序中,对于数据的输入/输出操作以“流( ...
- Java的IO流以及输入流与输出流的异同
一:流的基本概念: Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.J ...
- Java - 文件(IO流)
Java - 文件 (IO) 流的分类: > 文件流:FileInputStream | FileOutputStream | FileReader | FileWriter ...
- Java中IO流的总结
有关Java中IO流总结图 流分类 按方向分 输入流 输出流 按单位分 字节流 字符流 按功能分 节点流 处理流(过滤流) 其他 所有的流继承与这四类流:InputSteam.OutputStream ...
随机推荐
- ECMAScript中的原型继承
//ECMAScript中的原型继承//ECMAScript中的继承主要是依靠原型链实现的.(关于原型链的介绍,详见<高三>6.3.1章节 P162) //本文示例主要为了说明SubTyp ...
- Ubuntu18.04通过网线共享网络
Ubuntu18.04通过网线共享网络 这几天要给实验室一个新电脑装系统,但是实验室路由器好像有点问题,所以决定共享我的笔记本的网络,但是搜了很多教程都是基于Ubuntu16.04的,而Ubuntu1 ...
- JavaScript随机验证码
利用canvas制作一个随机验证码: 1.clearRect:context.clearRect(x,y,width,height);清空给定矩形内的指定像素 2.fillStyle:设置画笔的颜色 ...
- 用python 打印出爱心
其实,如果程序员真的很浪漫,普通人不懂,科技兴旺,也许你是惊呆了!!!!! 今天,泰泰又给你带来了一个“程序员技术(浪漫)表现”教程.飞鲸水龙头有希望它能在这个七月前夜帮到你.如果使用成功,记得给泰泰 ...
- es 启动报错 内存太小
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] elastics ...
- Python3简易接口自动化测试框架设计与实现(中)
目录 7.Excel数据读取 7.1.读取配置文件 7.1.编写Excel操作类 8.用例组装 9.用例运行结果校验 10.运行用例 11 .小结 上一篇:Python3简易接口自动化测试框架设计与实 ...
- 【6】Zookeeper脚本及API
一.客户端脚本 1.1.客户端连接 cd /usr/local/services/zookeeper/zookeeper-3.4.13/bin ##连接本地Zookeeper服务器 sh zkCli. ...
- 01_Redis简述
一:关系型数据库和非关系型数据库的区别: 1:关系型数据库(SQL):数据和数据之间,表和字段之间,表和表之间是存在关系的: 优点:数据之间有关系,进行数据的增删改查时非常方便的:关系型数据库有事务操 ...
- jsp下拉列表
<c:set var="REPORT_TYPE_NORMAL" value="<%=SysIndexFormTemp.REPORT_TYPE_NORMAL%& ...
- udp单播,广播,多播实现(ReceiveFromAsync,SendToAsync)
注意:客户端和服务器实现基本一致,本地host和port和多播的host和port可以一样 (1)多播 1.将本地host加入多播组中,只有加入多播组的成员才能接受同组的节点发送的多播 Multica ...