`
wangqiang6028
  • 浏览: 87742 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Java的IO操作

 
阅读更多

 

本篇日志主要讲述与IO相关的内容,对视频中的知识点进行归纳、总结、扩充。同时列举几个简单的例子。

 

IO流的分类

   Java的IO主要包含三个部分:

  • 流式部分――IO的主体部分;
  • 非流式部分――主要包含一些辅助流式部分的类,如:File 类、RandomAccessFile类和FileDescriptor等类;
  • 文件读取部分的与安全相关的类, 如:SerializablePermission类。以及与本地操作系统相关的文件系统的类;

  流式部分可以概括为:两个对应一个桥梁。两个对应指:

  • 字节流(Byte Stream)和字符流(Char Stream)的对应;
  • 输入和输出的对应。一个桥梁指:从字节流到字符流的桥梁。对应于输入和输出为InputStreamReader和 OutputStreamWriter。

在流的具体类中又可以具体分为:

  • 介质流(Media Stream或者称为原始流Raw Stream)――主要指一些基本的流,他们主要是从具体的介质上,如:文件、内存缓冲区(Byte数组、Char数组、StringBuffer对象) 等,读取数据;
  • 过滤流(Filter Stream)――主要指所有FilterInputStream/FilterOutputStream和FilterReader /FilterWriter的子类,主要是对其包装的类进行某些特定的处理,如:缓存等。
Java IO流对象

1、输入字节流InputStream

下面是IO中输入字节流的继承图。



 在上面的关系图中可以看出:

1、InputStream是所有的输入字节流的父类,它是一个抽象类。
2、 ByteArrayInputStream、StringBufferInputStream、FileInputStream是三种基本的介质流,它们分别将Byte数组、StringBuffer、和本地文件中读取数据。
3、 ObjectInputStream和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。下表列出了这些流的功能及如何使用它们。
基本输入字节流:
功能 构造及使用
ByteArrayInputStream 将内存中的Byte数组适配为一个InputStream

从内存中的Byte数组创建该对象(2种方法)

一般作为数据源,会使用其它装饰流提供额外的功能,一般都建议加个缓冲功能。

StringBufferInputStream 将内存中的字符串适配为一个InputStream

从一个String对象创建该对象。底层的实现使用StringBuffer。该类被Deprecated。主要原因是StringBuffer不应该属于字节流,所以推荐使用StringReader

一般作为数据源,同样会使用其它装饰器提供额外的功能。

FileInputStream 最基本的文件输入流。主要用于从文件中读取信息。

通过一个代表文件路径的 StringFile对象或者 FileDescriptor对象创建。

一般作为数据源,同样会使用其它装饰器提供额外的功能。

PipedInputStream 读取从对应PipedOutputStream写入的数据。在流中实现了管道的概念。

利用对应的PipedOutputStream创建。

在多线程程序中作为数据源,同样会使用其它装饰器提供额外的功能。

SequenceInputStream 2个或者多个InputStream 对象转变为一个InputStream。

使用两个InputStream 或者内部对象为InputStream Enumeration对象创建该对象。

一般作为数据源,同样会使用其它装饰器提供额外的功能。

FilterInputStream 给其它被装饰对象提供额外功能的抽象类。 主要子类见下表

 

装饰、输入字节流:

 类  功能  构造及使用
 DataInputStream  一般和DataOutputStream配对使用,完成基本数据类型的读写。

 利用一个InputStream构造。

提供了大量的读取基本数据类新的读取方法。

 BufferedInputStream  使用该对象阻止每次读取一个字节都会频繁操作IO。将字节读取一个缓存区,从缓存区读取。

 利用一个InputStream、或者带上一个自定义的缓存区的大小构造。

使用InputStream的方法读取,只是背后多一个缓存的功能。设计模式中透明装饰器的应用。

 LineNumberInputStream  跟踪输入流中的行号。可以调用getLineNumber( ) setLineNumber(int)方法得到和设置行号。

 利用一个InputStream构造。

紧紧增加一个行号。可以象使用其它InputStream一样使用。

 PushbackInputStream  可以在读取最后一个byte 后将其放回到缓存中。

 利用一个InputStream构造。

一般仅仅会在设计compilerscanner 时会用到这个类。在我们的java语言的编译器中使用它。很多程序员可能一辈子都不需要。

 

1、输出字节流OutputStream

下面是IO中输出字节流的继承图。

 在上面的关系图中可以看出:

1、OutputStream是所有的输出字节流的父类,它 是一个抽象类;
2、 ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte数组、和本地文件中写入数据。 PipedOutputStream是向与其它线程共用的管道中写入数据;
3、 ObjectOutputStream和所有FilterOutputStream的子类都是装饰流。下表列出了输出字节流的功能及如何使用它们。

 

功能 构造及使用
ByteArrayOutputStream 在内存中创建一个buffer。所有写入此流中的数据都被放入到此buffer中。

无参或者使用一个可选的初始化buffer的大小的参数构造。

一般将其和FilterOutputStream套接得到额外的功能。建议首先和BufferedOutputStream套接实现缓冲功能。通过toByteArray方法可以得到流中的数据。

FileOutputStream 将信息写入文件中。

使用代表文件路径的StringFile对象或者 FileDescriptor对象创建。还可以加一个代表写入的方式是否为append的标记。

一般将其和FilterOutputStream套接得到额外的功能。

PipedOutputStream 任何写入此对象的信息都被放入对应PipedInputStream 对象的缓存中,从而完成线程的通信,实现了管道的概念。具体在后面详细讲解。

利用PipedInputStream构造。

在多线程程序中数据的目的地的。一般将其和FilterOutputStream套接得到额外的功能。

FilterOutputStream 实现装饰器功能的抽象类。为其它OutputStream对象增加额外的功能。
主要子类见下表

 

装饰输出字节流:

 

功能 构造及使用
DataOutputStream 通常和DataInputStream配合使用,使用它可以写入基本数据类新。

使用OutputStream构造。

包含大量的写入基本数据类型的方法。

PrintStream 产生具有格式的输出信息。 使用OutputStream和一个可选的表示缓存是否在每次换行时是否flush的标记构造。还提供很多和文件相关的构造方法。
BufferedOutputStream 使用它可以避免频繁地向IO写入数据,数据一般都写入一个缓存区,在调用flush方法后会清空缓存、一次完成数据的写入。

从一个OutputStream或者和一个代表缓存区大小的可选参数构造。

提供和其它OutputStream一致的接口,只是内部提供一个缓存的功能。

 

 字节流的输入与输出的对应 

 下图表示字节流部分的输入与输出的对应关系

 
上图中蓝色的为主要的对应部分,红色的部分就是不对应部分。从上面的图中可以看出Java IO中的字节流是极其对称的。下面看看这些字节流中不太对称的几个类:

  •  LineNumberInputStream 主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部 分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行 号;
  • PushbackInputStream的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分;
  •   StringBufferInputStream已经被Deprecated,本身就不应该出现在InputStream部分,主要因为String应该属于字符流的范围;
  • SequenceInputStream可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取;
  •  PrintStream 也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream写入数据,本身内部实现还是带缓冲的。

蓝色的部分是IO字节流的主要组成部分,存在极强的对称关系。关于搭配使用的三对类补充 一下:ObjectInputStream/ObjectOutputStream和DataInputStream/DataOutputStream 主要是要求写对象/数据和读对象/数据的次序要保持一致,否则轻则不能得到正确的数据

 

IO中的输入字符流

    下面是IO中输入字符流的继承图:

 

 在上面的关系图中可以看出:

  •  Reader是所有的输入字符流的父类,它是一个抽象类;
  • CharReaderStringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据;
  • BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象;
  • FilterReader是所有自定义具体装饰流的父类,其子类PushbackReaderReader对象进行装饰,会增加一个行号;
  • InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流;

IO中的输出字符流

下面是IO中输出字符流的继承图:

 在上面的关系图中可以看出:

  •  Writer是所有的输出字符流的父类,它是一个抽象类;
  • CharArrayWriterStringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据;
  • BufferedWriter是一个装饰器为Writer提供缓冲功能;
  • PrintWriterPrintStream极其类似,功能和使用也非常相似;
  • OutputStreamWriterOutputStreamWriter转换的桥梁,它的子类FileWriter其实就是一个实现此功能的具体类。
字符流的输入与输出的对应

 

下图为字符流的输入与输出的对应关系图:

 

 

 下面例举一些实例来对上面总结的知识点进行应用:

   以下是BufferedInputStream和BufferedOutputStream的应用举例

  复制媒体文件:
//通过字节流缓冲区来复制文件
public static void Copy_Mp3()throws IOException{ //运行1504ms
	FileInputStream fs=new FileInputStream("E:/Wildlife.wmv");
	FileOutputStream fos=new FileOutputStream("E:/s.wmv");
	BufferedInputStream bs=new BufferedInputStream(fs);//装饰类进行封装,提供更强大的功能,注意两者都接受了相应的流对象作为参数
	BufferedOutputStream bos=new BufferedOutputStream(fos);
	MyBufferedInputStream bs=new MyBufferedInputStream(fs);//自定义的缓冲区类,运行986ms
	int num=0;
	while((num=bs.read())!=-1){//read()方法是将byte类型的数据转换为int类型,避免目标文件的第一个字节数据全部为1,即连续八个1所带来的影响
		bos.write(num);//write()方法将int类型的数据强制转换为byte类型,即只保留低8位数据,丢弃高24位数据;
	}
	bs.close();
	bos.close();
	System.out.println("copy over!");
}

 

然后,研究一下BufferedWriter和BufferedReader,它们分别和Writer体系的类及Reader体系的类相对性,也属于装饰类,主要用于文本操作,可以提高效率。

BufferedReader应用
/*
 * 字符读取流缓冲区;
 * 该缓冲区提供了一个一次读一行的方法readine,方便于对文本数据的获取。
 * 当返回null时,表示读到文件末尾
 * readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符
 */

import java.io.*;
public class BufferedReaderDemo {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		//创建一个读取流对象和文件相关联
		FileReader fr=new FileReader("E:/tttt.txt");
		//为了提高效率,加入了缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
		MyBufferedReaderDemo br=new MyBufferedReaderDemo(fr);//测试自定义的缓冲器
		BufferedReader br=new BufferedReader(fr);//java提供的缓冲区类
		String str=null;
		while((str=br.ReadLine())!=null){//readLine()返回的是字符串,其实它是自行把字符数组转化为字符串
			System.out.println(str);
		}
	}
}

 

BufferedWriter应用
import java.io.*;
public class BufferWriterDemo {

	//创建一个字符写入流对象
	//为了提高字符写入流数据效率,加入了缓冲去技术。
	//只要将需要被提高效率的流对象作为 参数传递给缓冲区的构造函数即可
	public static void main(String[]args)throws IOException{
		FileWriter fw=new FileWriter("e:/tttt.txt");
		BufferedWriter bw=new BufferedWriter(fw);
		for(int i=0;i<=10;i++)
		{
		bw.write("sdfsdfsdf");
		bw.newLine();//提供一个换行字符,BufferedReader在读取字符时,会忽略换行符,所以用newline()方法人为的添加换行符,在windows里换行符为'\r''\n'
		//在别的系统平台上换行符是不一样的,为了跨平台的需要,可以用此方法人为的提供换行符
                bw.flush();//将其实时的写入指定的文件,防止意外事件导致数据没有及时的写入文件
		}
		bw.close();//其实关闭缓冲区,就是关闭缓冲区中的流对象
	}
}

 

关于基本的装饰类就介绍到这里,接下来我们谈谈一种比较特殊的类InputStreamReader和OutputStreamWriter.

 

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
这样给我们带来很大的方便就是之前我们是用的FileInputStreamReader是使用的系统默认编码,我们无法改变,而InputStreamReader可以让我们自由的指定字符编码。

 

下面是 InputStreamReader的简单实例 

/*
 * 键盘录入数据
 * 当键盘录入一行数据时,我将其打印在控制台上
 * 当输入over时,录入工作结束
 */
import java.io.*;
public class ReadIn {

	public static void main(String[] args)throws IOException {
		// TODO Auto-generated method stub
		InputStream in=System.in;//System.in是InputStream类型,系统默认的数据源为键盘
		StringBuilder buf=new StringBuilder();
		int num;
		while(true){
			num=in.read();
			if(num=='\r')continue;
			if(num=='\n'){
				if("over".equals(buf.toString()))break;//当输入over是,程序退出
				System.out.println(buf.toString());
				buf.delete(0, buf.length());//每读完一次,则清楚buf里面的内容,为下一次读取做准备
			}
			else buf.append((char)num);
		}
		System.out.println("sdf");
	}
}

 

 看下两个的简单综合应用 
/*
 * 字符流:FileReader,FileWriter
 * BufferedReader,BufferedWriter
 * 字节流:FileInputStream,FileOutPutStream
 * BufferedInputStream,BufferedOutputStream
 * 本功能实现用Readline方法从控制台一次读取一行数据
 */
import java.io.*;
public class TransStreamDemo {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		//获取键盘录入对象。
		/*InputStream in=System.in;
		//将字节流对象转成字符流对象,使用转换流。InpuStreamReader
		InputStreamReader is=new InputStreamReader(in);
		//为了提高效率,将字符串进行缓冲区技术提高操作
		BufferedReader os=new BufferedReader(is);
		*/
		BufferedReader os=new BufferedReader(new InputStreamReader(System.in));//简写
		String line;
		/*OutputStream out=System.out;
		OutputStreamWriter osw=new OutputStreamWriter(out);
		BufferedWriter buw=new BufferedWriter(osw);*/
		BufferedWriter buw=new BufferedWriter(new OutputStreamWriter(System.out));//简写,System.out的默认输出到控制台
		while((line=os.readLine())!=null){
			if("over".equals(line))break;
			//System.out.println(line);
			buw.write(line);
			buw.newLine();
			buw.flush();
		}
		System.out.print("it's over");
	}
}

 

还有个可以输出行号的缓冲类LineNumBufferedWriter ,在上面的总结中已经详细介绍了,下面通过代码来看它的使用:

/*
 * 带行号的缓冲区类,继承于BufferedReader
 */
import java.io.*;
public class LinkNumberReaderDemo  {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		FileReader fr=new FileReader("E:/tttt.txt");
		MyLineNumberReader lr=new MyLineNumberReader(fr);//测试自己模拟的类
		//LineNumberReader lr=new LineNumberReader(fr);
		String str=null;
		lr.setLineNumber(10);
		while((str=lr.readLine())!=null){
			System.out.println(lr.getLineNumber()+":"+str);
		}
	}
}

 

其实LineNumBufferedWriter 的用法和其他几个都差不多,只是多了一个可以输出行号的功能。

 

 

  • 大小: 36 KB
  • 大小: 30.8 KB
  • 大小: 59.9 KB
  • 大小: 26.4 KB
  • 大小: 29.3 KB
  • 大小: 55.2 KB
分享到:
评论

相关推荐

    javaIO操作简单例子

    下面是一个简单的Java IO操作示例,展示如何使用InputStream和FileOutputStream进行文件的复制: ```java import java.io.*; public class SimpleIOTest { public static void main(String[] args) { try { ...

    提高Java IO操作的性能

    提高Java IO操作的性能 虽然抱怨Java程序性能不佳的呼声由来已久,但实际上,如果开发者在整个开发周期内都能够关注性能问题,Java程序完全可以和C/C++程序一样快。本文分析了Java IO应用中一些常见的性能问题。

    常用java IO操作以及用jxl读写excel 工具源代码

    Java IO操作是Java编程中非常基础且重要的部分,它提供了对输入输出流的处理,使得程序能够与外部设备(如硬盘、网络、键盘、显示器等)进行数据交换。本工具结合了Java IO操作和JXL库,实现了读取Excel文件并进行...

    javaIo操作的基础代码

    Java IO操作是Java编程中的重要组成部分,主要用于处理输入和输出数据。在Java中,IO操作涉及到文件、字节流、字符流以及管道流等多个概念。下面将详细解释这些知识点。 首先,我们来看“文件类”。在Java中,`java...

    JAVAIO操作总结

    Java IO操作是Java编程中非常重要的一个部分,它主要用于数据的输入输出,包括从文件、网络、内存等来源获取数据,以及向这些目的地发送数据。本文将对Java IO中的节点流和处理流进行详细的总结。 首先,我们来看...

    javaIO操作入门

    本教程旨在为初学者提供Java IO操作的基础知识,帮助他们入门并理解这一核心概念。 Java IO库包含了大量类和接口,主要分布在java.io包中,它们提供了对输入输出流的支持。输入流用于从源获取数据,而输出流则用于...

    java io操作大全

    Java IO操作大全主要涵盖对文件和数据的输入输出管理,涉及多种流的使用以及对象序列化等关键概念。下面将详细解析这些知识点。 首先,Java中的IO操作主要基于`java.io`包,这个包提供了丰富的类和接口来处理输入...

    java线程+java IO操作

    Java线程和IO操作是Java编程中的核心概念,它们在构建高效、响应迅速的应用程序时起着至关重要的作用。在Java中,线程用于实现并发执行,而IO操作则涉及数据的读取和写入。这两者结合可以创建能够同时处理多个输入/...

    图书管理系统(java IO操作)

    《图书管理系统:基于Java IO操作的实现》 在IT领域,图书管理系统是一个常见的应用场景,它主要用于图书馆或书店的日常运营,如图书的入库、出库、借阅、归还等管理。本系统采用三层架构设计,分别是表现层、业务...

    java io 操作总结

    Java IO操作是Java编程中用于处理数据输入和输出的标准方式。它提供了一组丰富的类和接口,用于读取和写入数据到各种类型的I/O流。在这篇总结中,我们将探讨Java IO操作的各个方面,包括File类、RandomAccessFile类...

    java IO操作总结

    ### Java IO操作总结 Java IO(输入/输出)是Java编程语言中用于处理数据输入和输出的核心机制。本文档全面总结了Java IO的各种操作,旨在为开发者提供一个深入理解并熟练掌握Java IO技术的资源。 #### 一、临时...

    java io 操作

    Java IO操作是Java编程语言中一个非常重要的领域,它涵盖了数据的输入与输出,包括从文件、网络、内存等不同来源读取数据以及向这些地方写入数据。在这个主题中,我们将深入探讨Java IO的基本概念、核心类库、常用...

    JavaIO操作的实例代码.pdf

    以下是对给定文件中几个Java IO操作实例代码的详细解释: 1. `TestFileInputStream` 类展示了如何使用 `FileInputStream` 读取文件内容。在读取文件时,需要注意编码问题。当读取包含中文字符的文件时,如果直接...

    Java IO操作和将字符串解析为数值数组

    首先,Java IO操作包括对文件、网络、系统流等的读写操作。核心类库提供了一系列接口和类,如`InputStream`、`OutputStream`、`Reader`、`Writer`以及`File`等。在Java中,我们通常使用`BufferedReader`和`...

    java的io操作

    Java的IO操作是Java编程中不可或缺的一部分,它允许程序与外部存储设备进行交互,如读取文件、写入文件、创建文件夹等。在Java中,`java.io`包提供了大量的类和接口来支持这些功能。 首先,我们来看如何创建一个新...

    java IO操作 (读写、追加、删除、移动、复制) 源码集合

    这个源码集合展示了Java IO操作的基本用法,对于学习和理解Java文件操作非常有帮助。通过这些基础操作,开发者可以构建复杂的数据处理流程,例如日志记录、文件备份、数据迁移等。在实际开发中,应根据具体需求选择...

    javaIO操作(读写、追加、删除、移动、复制、修改).pdf

    Java IO操作是Java编程中至关重要的一部分,它允许程序与外部存储设备进行数据交互,包括读取、写入、追加、删除、移动、复制和修改文件。在给定的文件内容中,我们可以看到几个关键的Java IO操作示例。 首先,`...

Global site tag (gtag.js) - Google Analytics