`
yidongkaifa
  • 浏览: 4060580 次
文章分类
社区版块
存档分类
最新评论

Java I/O流操作(二)---缓冲流

 
阅读更多
IO的缓冲区的存在就是为了提高效率,把要操作的数据放进缓冲区,然后一次性把缓冲区的内容写到目的地,而不是写一次就往目的地写一次.
在这里要注意的是当我们关闭了缓冲区对象实际也关闭了与缓冲区关联的流对象.
BufferWriter
FileWriter fw =null;
try{
fw =newFileWriter("test.txt");
//使用缓冲区必须要与一个流对象相关联
BufferedWriter bw =newBufferedWriter(fw);
bw.write("hello world!");
//使用缓冲区的时候要注意刷新
bw.flush();
//关闭缓冲区的对象,实际上是关闭与它关联的流对象最好放在finally执行
bw.close();
}catch(IOException e) {
e.printStackTrace();
}
其实BufferReader也是差不多的,这里就不多讲
FileReader fr =newFileReader("test.txt");
BufferedReader br =newBufferedReader(fr);
String line =null;
//注意readLine方法读取的内容不包括换行符
while((line=br.readLine())!=null){
System.out.println(line);
}
readLine原理:
无论是读一行,获取多个字符,最终都是在硬盘上一个一个读取,所以最终使用的还是read方法一次读一个的方法.
装饰模式:
class Person{
public void eat(){
System.out.println("吃饭");
}
}
public class PersonEnhance{
private Person p;
//把需要增强 的类传进去初始化
public PersonEnhance(Person p){
this.p=p;
}
public void enhanceEat(){
System.out.println("开胃酒");
p.eat();
System.out.println("甜点");
}
}
装饰模式就是在原有类的基础上把某个方法增强功能
但是这让我想到了java 的动态代理,他也是在某个方法的基础上增加额外的功能,那么她们有什么区别呢?
装饰类和被装饰的类是应该继承或实现相同的接口,而java的动态代理不是,
还有一个不同点就是动态代理可以横切多个面,也就是同时对多个方法进行增强.
通过装饰模式和继承的区别发现了程序设计之美,虽然继承也可以增强某个方法,但是它使得类的体系很臃肿,并且可扩展性不好
因为装饰模式中,我们可以把被装饰类的父类当作参数传进装饰类的构造方法内,那么你这一个装饰类就可以应用于这个体系的了,这也是java多态性的好处.
相比较之下使用装饰模式降低了类之间的关系.
装饰类是因为增强了已有的对象,具有的功能和已有的是相同的,是不过提供了更强的功能,所以装饰类和被装饰类通常属于一个体系中的.
在API中可以看到BufferedReader类还有一个子类LineNumberReader

通过API对得知,这是一个字符缓冲输出流,该类保持对行号的跟踪,可以通过该类的setLineNumber(int)andgetLineNumber()方法分别设置获取行号
例如程序:
publicstaticvoidmain(String[] args)throwsIOException{
FileReader fr =newFileReader("test.txt");
LineNumberReader lnr =newLineNumberReader(fr);
String num =null;
while((num=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+":"+num);
}
}
控制台输出:

但是我们也可以改变行号的开始值
publicstaticvoidmain(String[] args)throwsIOException{
FileReader fr =newFileReader("test.txt");
LineNumberReader lnr =newLineNumberReader(fr);
String num =null;
//设置行号的开始值为100
lnr.setLineNumber(100);
while((num=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+":"+num);
}
}
输出结果为:

LineNumberReader
EnhanceLineNumberReader
publicString readLine()throwsIOException {
lineNumber++;
StringBuilder buffer =newStringBuilder();
inti = 0;
while((i =reader.read()) != -1) {
if((char) i =='\r') {
continue;
}
if((char) i =='\n') {
returnbuffer.toString();
}else{
buffer.append((char) i);
}
}
if(buffer.length() != 0) {
returnbuffer.toString();
}
returnnull;
}
书出结果是一样的
下面开始学习字节流
通过API文档字节流的顶级类为InputStream和OutputStream
首先来看一下FileOutputStream和FileInputStream
publicstaticvoidwriteData()throwsException{
OutputStream out =newFileOutputStream("D:\\test2.txt");
out.write("hello inputStream!".getBytes());
}
执行上面代码后,发现在D盘创建了test2.txt文件并且内容是hello inputStream!
从上面可以看出这和字符流是有区别的,因为当我们在使用字符流的时候,如果没有刷新并且没有关闭那么文件内容是空的,而这里刚好相反.
但是最好我们还是调用close方法,关闭资源.提高性能.
下面实现读取操作
public static void readData() throws Exception {
InputStream is = new FileInputStream("D:\\test2.txt");
int num = 0;
while ((num = is.read()) != -1) {
System.out.println((char) num);
}
}
但是这样效率比较低,因为读取一次写一次,我们可以使用缓冲
publicstaticvoidreadData2()throwsException {
InputStream is =newFileInputStream("D:\\test2.txt");
intnum = 0;
byte[] buffer =newbyte[1024];
//把读取到的数据放进字节数组里面
while((num = is.read(buffer)) != -1) {
System.out.println(newString(buffer, 0, num));
}
}
在InputStream类中有这样一个方法available()返回int 他的作用是返回文件内容的长度 那么我们就可以这样读取数据,而不用while循环了
publicstaticvoidreadData3()throwsException {
InputStream is =newFileInputStream("D:\\test2.txt");
//返回文件的长度
intnum = is.available();
把字节数组的长度定义成文件长度,那么这个数组就刚好装下这个文件了
byte[] buffer =newbyte[num];
is.read(buffer);
System.out.println(newString(buffer));
}
但是这样有一个缺陷,如果一个文件非常大,那么这就会出现内存溢出了.所以这是用操作小型 的文件.
练习,复制一份图片:代码片段:
InputStream is = new FileInputStream("D:\\imagetest\\desk.jpg");
OutputStream os = new FileOutputStream("E:\\desk1.jpg");
byte[] buffer = new byte[1024];
int readNum = 0;
int a=0;
while((readNum=is.read(buffer))!=-1){
System.out.println(a++);
os.write(buffer, 0, readNum);
}
使用java缓冲输出流
BufferedOutputStreambuffOs =newBufferedOutputStream(newFileOutputStream("F:\\KuGou\\baby2 - baby one more time.mp3"));
BufferedInputStreambuffIs =newBufferedInputStream(newFileInputStream("F:\\KuGou\\baby - baby one more time.mp3"));
intlen = 0;
while((len=buffIs.read())!=-1){
buffOs.write(len);
}
buffOs.close();
buffIs.close();
获取键盘录入:
System.out对应的是标准的输出设备一般指控制台
System.in对应的是标准输入设备:键盘
下面模拟一个键盘录入的功能:
publicstaticvoidmain(String[] args)throwsIOException {
InputStream is = System.in;
StringBuilder buffer =newStringBuilder();
inti = 0;
while(true) {
i = is.read();
if('\r'== i)
continue;
if('\n'== i) {
String value = buffer.toString();
//如果录入的是over那么则退出
if("over".equals(buffer.toString()))
break;
System.out.println(value);
//清空缓冲区 以免下次录入时不会和前面录入的汇合
buffer.delete(0, buffer.length());
}
else{
buffer.append((char)i);
}
}
}
注意在输入流在读取数据的时候连回车也会读取的.在windows中\r\n代表换行 例如下面简单的程序
InputStream is = System.in;
System.out.println(is.read());
System.out.println(is.read());
控制台输出:
13
10
对于键盘录入功能我们可以使用更加简单的方式:因为他这个功能实际上就是读取一行 的操作:
那么就可以考虑使用readLine方法,然后该方法是字符六BufferedReader的方法
然而InputStream又是字节流.那么怎么办呢?
我们可以使用InputStreamReader类,这个类是字节流到字符流的桥梁,
publicstaticvoidmain(String[] args)throwsIOException {
InputStream is = System.in;
InputStreamReader isr =newInputStreamReader(is);
BufferedReader br =newBufferedReader(isr);
String line =null;
while((line=br.readLine())!=null){
if(line.equals("over")){
break;
}
System.out.println(line.toUpperCase());
}
}
对应的OutputStreamWriter是字符流向字节流转换的桥梁 也就是读进来的是字符,写进去的是字节,在上面的基础上我们可以这样改写:
publicstaticvoidmain(String[] args)throwsIOException {
InputStream is = System.in;
InputStreamReader isr =newInputStreamReader(is);
BufferedReader br =newBufferedReader(isr);
OutputStreamWriter osw =newOutputStreamWriter(System.out);
BufferedWriter bw =newBufferedWriter(osw);
String line =null;
while((line=br.readLine())!=null){
if(line.equals("over")){
break;
}
bw.write(line);
//注意使用字符流要注意flush
bw.flush();
//System.out.println(line.toUpperCase());
}
}
但是控制台输出为:

发现输出的数据没有换行
当然我们可以在line后面加上\r\n
但是这是不跨品台的
我们可以这样解决:
我们可以使用
BufferedWriter 的newLine方法
在bw.write(line);后面加上bw.newLine();即可
总结: 下面总结一下IO的操作规律:
1,明确源和目的:
源 :输入流,InputStream Reader
目的: 输入流 OutpuStream Writer
3当明确体系后,在明确使用哪个具体的对象
通过设备来进行区分:
源设备: 存 硬盘 键盘
目的设备: 内存 硬盘 控制台
分享到:
评论

相关推荐

    Java I/O底层是如何工作的?

    本文服务的读者,迫切希望了解Java I/O操作是在机器层面如何进行映射,以及应用运行时硬件都做了什么。假定你熟悉基本的I/O操作,比如通过Java I/O API读写文件。这些内容不在本文的讨论范围。  目录  缓存处理...

    基础深化和提高-IO流技术学习大全

    Java的I/O流(Input/Output Stream)技术是Java编程中用于处理输入和输出的重要部分。它提供了一种灵活而统一的方式来与文件、网络连接、内存等进行数据交换。 I/O流主要分为两种类型:字节流和字符流。 字节流: ...

    java nio超好资源

    NIO 的创建目的是为了让 Java 程序员可以实现高速 I/O 而无需编写自定义的本机代码。NIO 将最耗时的 I/O 操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度。

    使用Buffer进行II/O操作

    使用缓冲组件对文件I/O进行包装,可以有效的提升文件的I/O性能。

    基于java NIO的简单聊天软件示例

    NIO是一种基于通道和缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存(区别于JVM的运行时数据区),然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的直接引用进行操作。这样能在一些...

    java nio 中文版

    第二章 缓冲区 第三章 通道 第四章 选择器 第五章 正则表达式 第六章 字符集 --------------------- 作者:仓鼠洞 来源:CSDN 原文:https://blog.csdn.net/zhiyong499/article/details/78711911 版权声明...

    JAVA_API1.6文档(中文)

    javax.imageio.stream Java Image I/O API 的一个包,用来处理从文件和流中产生的低级别 I/O。 javax.management 提供 Java Management Extensions 的核心类。 javax.management.loading 提供实现高级动态加载的类...

    javalru笔试题-jaydio:在Linux中执行直接I/O的Java库,绕过文件页面缓存

    I/O,部分是通过绕过操作系统缓冲区缓存。 目前,仅支持 Linux 。 Jaydio 作为异步/非阻塞直接 I/O、自定义文件页面缓存层,甚至高级缓存替换策略(如 或 )的起点。 目前,它可用于防止操作系统驱逐需要保持“热”...

    新输入输出(NIO)

    JDK 1.4 中引入的新输入输出 (NIO) 库在标准 Java 代码中提供了高速的、面向块的 I/O。本实用教程从高级概念到底层的编程细节,非常详细地介绍了 NIO 库。您将学到诸如缓冲区和通道这样的关键 I/O 元素的知识,并...

    java jdk-api-1.6 中文 chmd

    javax.imageio.stream Java Image I/O API 的一个包,用来处理从文件和流中产生的低级别 I/O。 javax.management 提供 Java Management Extensions 的核心类。 javax.management.loading 提供实现高级动态加载的类...

    java_I\O学习笔记

    java_I\O学习笔记 主要讲的是字节流以及缓冲流的操作

    java各知识点详细总结.docx

    文件读写:Java中的文件读写包括输入输出流、文件类、缓冲流等。Java中的文件读写可以通过Java I/O API来实现。 多线程编程:Java中的多线程编程是一种实现并发程序的方法。Java中的多线程通过创建线程对象和实现...

    java深度历险

    序 1 目录 2 JAVA字节代码的操纵 4 动态编译JAVA源文件 4 ...JAVA I/O 45 流 45 缓冲区 47 字符与编码 48 通道 49 参考资料 52 JAVA安全 53 认证 53 权限控制 55 加密、解密与签名 57 安全套接字连接 58 参考资料 59

    新输入输出NIO

    JDK 1.4 中引入的新输入输出 (NIO) 库在标准 Java 代码中提供了高速的、面向块的 I/O。本实用教程从高级概念到底层的编程细节,非常详细地介绍了 NIO 库。您将学到诸如缓冲区和通道这样的关键 I/O 元素的知识,并...

    NIO入门学习

    JDK 1.4 中引入的新输入输出 (NIO) 库在标准 Java 代码中提供了高速的、面向块的 I/O。本实用教程从高级概念到底层的编程细节,非常详细地介绍了 NIO 库。您将学到诸如缓冲区和通道这样的关键 I/O 元素的知识,并...

    Java 1.6 API 中文 New

    javax.imageio.stream Java Image I/O API 的一个包,用来处理从文件和流中产生的低级别 I/O。 javax.management 提供 Java Management Extensions 的核心类。 javax.management.loading 提供实现高级动态加载的类。...

    JAVA SE 开发手册.CHM

    1、JDK的安装和环境变里的配置 2. HelloWorld程序 3、JAVA的数据类型及转换 4、JAVA运算符 5、JAVA控制语句结构 6、JAVA数组及查找和排序 ...20、I0流之字符流、字节流、转换流、缓冲流、对象流 21,I0流之HIO

    MySQL 5.1官方简体中文参考手册

    6.3.2. 复制从I/O线程状态 6.3.3. 复制从SQL线程状态 6.3.4. 复制传递和状态文件 6.4. 如何设置复制 6.5. 不同MySQL版本之间的复制兼容性 6.6. 升级复制设置 6.6.1. 将复制升级到5.0版 6.7. 复制特性和已知问题 6.8....

    java api最新7.0

    javax.imageio.stream Java Image I/O API 的一个包,用来处理从文件和流中产生的低级别 I/O。 javax.management 提供 Java Management Extensions 的核心类。 javax.management.loading 提供实现高级动态加载的类。...

    JavaAPI1.6中文chm文档 part1

    javax.imageio.stream Java Image I/O API 的一个包,用来处理从文件和流中产生的低级别 I/O。 javax.management 提供 Java Management Extensions 的核心类。 javax.management.loading 提供实现高级动态加载的类...

Global site tag (gtag.js) - Google Analytics