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 ...
随机推荐
- NVIDIA双显卡
NVIDIA双显卡 第一步:代码:sudo update-pciids #更新显卡信息非常重要,否则可能识别出错lspci -v | grep -i vga #察看显卡 我的显卡信息如下:代码:00: ...
- vue组件之间的传值
vue中组件之间的传值有好几种情况 1.父向子传值 父组件向子组件传值使用props,直接上实例 city.vue是父组件,list.vue是子组件city.vue里定义cities和hotCitie ...
- 9.SpringMVC注解式开发-处理器的请求映射规则的定义
1.对请求URI的命名空间的定义 @RequestMapping的value属性用于定义所匹配请求的URI.但对于注解在方法上和注解在类上, 其value 属性 所指定的URI,意义是不同的 一个@C ...
- RabbitMQ的持久化
RabbitMQ的持久化主要体现在三个方面,即交换机持久化,队列持久化及消息持久化 注意,因公司使用php-amqplib来实现RabbitMQ,故之后举例说明的代码均使用的php-amqplib ...
- 【Mac】 开启原生的 NTFS 硬盘格式支持
一.MacOS 10.13 之前 二.MacOS 10.13 及之后 一.MacOS 10.13 之前 直接跳到引用地址查看,下面的草记只是为了防止链接丢失 引用地址 打开终端 切换至root身份,输 ...
- Django学习:创建admin后台管理站点
Django自带一个后台管理站点,方便我们管理数据.这个界面只给管理员使用,并不对大众开放. 创建管理员用户 py manage.py createsuperuser 如下图所示: 用户名不填的话,默 ...
- Unicode(统一码、万国码、单一码)
Unicode(统一码.万国码.单一码)是一种在计算机上使用的字符编码.它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言.跨平台进行文本转换.处理的要求.1990年开始研发,199 ...
- 集合(一)-Java中Arrays.sort()自定义数组的升序和降序排序
默认升序 package peng; import java.util.Arrays; public class Testexample { public static void main(Stri ...
- CF700E Cool Slogans——SAM+线段树合并
RemoteJudge 又是一道用线段树合并来维护\(endpos\)的题,还有一道见我的博客CF666E 思路 先把\(SAM\)建出来 如果两个相邻的串\(s_i\)和\(s_{i+1}\)要满足 ...
- IAR astyle代码美化
Menu Text填写上我们期望的名字,我们可以填入格式化代码,command内填入AStyle的地址, Argument内填入参数: --style=ansi -s4 -S -Y -D -xe ...