`

Java Io NIo (一) IO基础

阅读更多

一   I/O缓冲区

 

 

 用户空间:常规进程所在区域,JVM就是常规进程,该区域执行的代码不能直接访问硬件

                     设备

 

 内核空间:操作系统所在区域。内核代码它能与设备控制器通讯,控制着用户区域进程的运

                     行状态,等等。最重要的是,所有的I/O 都直接或间接通过内核空间

 

 数据交互:当用户(java)进程进行I/O操作的时候,它会执行一个系统调用将控制权移交给

                     内核,内核代码负责找到请求的数据,并将数据传送到用户空间内的指定缓冲区

 

 内核空间缓冲区:内核代码读写数据要通过磁盘的I/O操作,由于磁盘I/O操作的速度比直接访

                                 问内存慢了好几个数量级,所以内核代码会对数据进行高速缓存或预读取

                                 到内核空间的缓冲区(减少磁盘I/O,提高性能)

 

 用户空间缓冲区:同上,java I/O进程通过系统调用读写数据的速度,要比直接访问虚拟机内

                                 存慢好几个数量级,所以可以执行一次系统调用时,预读取大量数据,缓

                                 存在虚拟机内存中。

 

 

 

二  输入流InputStream、输出流OutputStream

  

      a) FileInputStream类实现了InputStream的读取单个字节read()、读取字节数组

             read(byte b[], int off, int len)的方法

             FileOutputStream类实现了OutputStream的写入单个字节write(int b)、写入字节数组

             write(byte b[], int off, int len)的方法(后面对Out介绍略过,参考In)            

		/**
		 *  文件输出流构造器
		 *  name 路径名
		 *  append 参数为true,数据将被添加到文件末尾,
		 *  而具有相同名字的已有文件不会被删除,否则这个方法删除所有具有相同名字的文件
		 */
	    public FileOutputStream(String name, boolean append)
	            throws FileNotFoundException
	        {
	            this(name != null ? new File(name) : null, append);
	        }

 

      b) 因为InputStream的实现类,只能读取字节,而且每次read都会执行一次系统调用,所

             以对其实现类进行扩展是必需的,过滤器FilterInputStream继承自InputStream,是一些

             扩展类(DataInputStream、BufferedInputStream)的基类。            

		public class FilterInputStream extends InputStream {
			protected volatile InputStream in;
			/**
			 * 构造方法受保护的,只能通过子类调用(初始化)
			 * 参数是InputStream的实现类,例:FileInputStream
			 */
		    protected FilterInputStream(InputStream in) {
		        this.in = in;
		    }

  

      c)   read()方法每次都会发起一次系统调用,而系统调用的代价是非常高的,所以为了

               减少系统调用的次数,就需要通过装饰器BufferedInputStream一次read()大量字节缓

               存在字节数组中。这里的缓存并不是为了减少磁盘IO操作次数,因为这个操作系统

               已经帮我们做了

		// 默认缓存8192字节=8kb,可以通过参数进行设置
		InputStream in = new BufferedInputStream(new FileInputStream("路径"), 8192);
		// 每次write()的字节,都会缓存到长度8912的字节数组中,直到写满才进行系统调用一次性写入
		OutputStream out = new BufferedOutputStream(new FileOutputStream("路径"), 8192);
		// 同理BufferedReader、BufferedWriter也是一样

 

       d)  数据在读取和写入时都是字节状态,适配器DataInputStream 实现了DataInput接口

                可以将读取的字节,在后台转换成java的基本类型然后进行读取,

                 例:readInt每次读取4个字节

	/**
     * DataInputStream类方法
	 * 转换成int类型,int4字节组成,一个字节8位
	 * 高位在前,进行数值还原
	 */
    public final int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

 

      e) DataOutputStream、DataInputStream两者一般结合使用,如果DataOutputStream 写

             入数据,java保证我们可以使用DataInputStream准确的读取数据。还有writeUTF()和

             readUTF()方法,可以对字符串进行写入、读取。 用到这两个类的来读写文件的数据格

             式一般比较固

		DataInputStream buff = new DataInputStream(
				               new BufferedInputStream(
				               new FileInputStream("路径")));

 

        f)read和write方法在执行时将阻塞,直到字节被读入或者写出。不过通常是因为网络

             繁忙。available()方法“在没有阻塞的情况下所能读取的字节数”,即当前可读取

             入的字节数量,那么下面这样就不会 阻塞

		// 对于文件,这意味着整个文件都可读取
		int bytesAvailable = in.available();
		if (bytesAvailable > 0) {
			byte[] bytes = new byte[bytesAvailable];
			in.read(bytes);
		}

        

       g)输入流InputStream、输出流OutputStram的几个方法        

	public static void main(String[] args) throws IOException {

		// ByteArrayInputStream 可以将一个字节数组转成输入流
		InputStream in = new ByteArrayInputStream("abcdefghi".getBytes());
		// 判断是否支持标记功能
		in.markSupported(); // true
		// 跳过2个字节
		in.skip(2);
		/**
		 * 在当前位置打标记,非所有流都支持(这个流支持) 
		 * 如果从输入流中已经读的字节数大于5个,则这个流允许忽略这个标记(这个流不支持)
		 */
		in.mark(5);
		// 跳过2个字节
		in.skip(2);
		System.out.println((char) in.read());// 输出:e
		// 返回到最后一个标记,随后read将重新读入这些字节。如果没有标记不被重置
		in.reset();
		System.out.println((char) in.read());// 输出:c
		// 超过5个字节被读取
		in.skip(4);
		// mark不失效
		in.reset();
		System.out.println((char) in.read());// 输出:c

		byte[] b = new byte[10];
		// 向b中塞4个字节,从b[5]开始
		in.read(b, 5, 4);
		// 关闭流
		in.close();

		// OutputStram
		OutputStream out = new ByteArrayOutputStream();
		// 冲刷输出流,也就是将所有缓冲的数据送到目的地
		out.flush();
		// 冲刷并关闭流
		out.close();

	}

   

 

三  字符输入流Reader、字符输出流Writer

   

      a) 不管磁盘还是网络传输,最小的存储单位都是字节,所以抽象类InputStream和

              OutputStream构成了输入/输出(I/O)类层次的基础。

 

      b) 基础的输出输入流仅支持8位的字节流,并且不能很好的处理16为的Unicode字符,

              由于Unicode用于字符国际化(java本身的char也是16的Unicode,即包含两个字

              节), 所以适配器InputStreamReader、OutputStreamWriter出现了,用于字节和

              字符之间的 转换。

		// ByteArrayInputStream 可以将一个字节数组转成输入流
		InputStream in = new ByteArrayInputStream("你好".getBytes());
		// 先转换成字符,然后用BufferedReader进行缓存
		BufferedReader br = new BufferedReader(new InputStreamReader(in));

      

      c) 字符就是大家都能看懂的文字(包括其它国家文字)、符号之类的,比如txt存储的

              都是字符。无法转换成字符的如图片、MP3

 

      d)  以字符格式写出数据,可以使用PrintWriter,还可以设置是否每次写入都冲刷

               输出流。print/println方法可以写入字符和java的基本类型

	/**
	 * 其中的一个私有构造器方法
	 * @param charset 以选定的字符编码,将Unicode字符转换成字节进行存储
	 * @param file  文件路径
	 * @throws FileNotFoundException
	 */
    private PrintWriter(Charset charset, File file)
            throws FileNotFoundException
        {
            this(new BufferedWriter(//对字符缓存
            	 new OutputStreamWriter( 
            	 new FileOutputStream(file), charset)),false);
        }

 

      e) 以字符格式读取数据,可以使用BufferedReader,有一个readLine()方法,每次读取一

              行。没有按java基本类型读取数据功能。

             下面是将字节按照GBK字符集格式转换成字符。

		BufferedReader buff = new BufferedReader(
				              new InputStreamReader(
				              new FileInputStream(path), "GBK")); 

 

      f) java.util.Scanner类可以按行读取数据,也可以按java基本类型读取数据。

 

      g) RandomAccessFile类可以在文件中任何位置查找和写入数据,适合大小已知的记录

              组成的文件。类中有一个表示下一个读入或写出的字节所处的位置,用seek()方法,

              可以设置指针在文件中的任意位置。其实现了DataOutput, DataInput接口,可以对

              java的基本类型进行读写。在使用该类时,一般要知道文件的排版。还有其大多

              功能都可以用nio取代

		//只能进行读入访问
		RandomAccessFile in = new RandomAccessFile(path, "r");
		//可以进行读入、写出访问
		RandomAccessFile inOut = new RandomAccessFile(path, "rw");

 

 

 

四  ZipInputStream和ZipOutputStream

  

	//压缩:写出到ZIP文件
	ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream("压缩文件路径.zip"));
	//压缩文件中的每一项都是一个ZipEntry对象
	ZipEntry entry = new ZipEntry("文件名字");
	//将ZipEntry添加到压缩文件中
	zipOut.putNextEntry(entry);
	//可以通过缓存流写入数据
	BufferedOutputStream outbuf = new BufferedOutputStream(zipOut);
	//还可以继续嵌套
	DataOutputStream dou = new DataOutputStream(outbuf);
	
	
	//解压:将文件从压缩文件中读出
	ZipInputStream zipIn = new ZipInputStream(new FileInputStream("压缩文件路径.zip"));
	//返回下一个ZipEntry对象,没有更多项返回null
	zipIn.getNextEntry();
	//可以通过缓存流读取数据
	BufferedInputStream inbuf = new BufferedInputStream(zipIn);
	//还可以继续嵌套
	DataInputStream din = new DataInputStream(inbuf);

       a) ZipInputStream不能一次解压整个压缩文件,只能一次一个ZipEntry 的解压。

              ZipOutputStream不能一次压缩一个文件夹,只能一次一个ZipEntry 的压缩。

 

      b) ZipInputStream的read方法再碰到当前ZipEntry结尾时返回-1,然后必须调用

              closeEntry来读入下一个ZipEntry 。写入时同理。

 

 

五 对象序列化

 

  a)java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并可以将

        转换的字节序列恢复为原来的对象,这种机制可以弥补不同操作系统之间的差异,可以在

        windows上序列化传到unix恢复


  b)java的远程方法调用RMI(Remote Mthod Invocation)就是通过序列化实现的,当远程对象

        发送信息时,需要通过对象序列化来传输参数和返回值

 

  c)对象序列化不紧可以保存对象的全景图,还能追踪对象内所包含的全部引用,并保存那

        些对象

 

   d)序列化时每个对象的引用都会关联一个序列号,相同对象的重复序列化,将被存储为对

         这个对象序列号的引用。反序列化时过程相反。

 

   e)在反序列化一个对象时,会拿其序列号与它所属类的当前序列号进行对比,不匹配,说明

         这个类在序列化后发生过变化,这涉及“版本管理”就不概述了

	public static void main(String[] args) throws IOException, ClassNotFoundException {

		// 序列化
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		// 创一个ObjectOutputStream 写出到指定的OutputStream
		ObjectOutputStream oos = new ObjectOutputStream(out);
		// 这个方法将存储指定对象的类、类的签名,以及这个类及其超类中所有非静态和非transient(瞬时)修饰的域的值
		oos.writeObject("实现Serializable接口的对象");
		oos.writeObject("可以序列化多个对象");

		// 反序列化
		byte[] bs = out.toByteArray();
		InputStream is = new ByteArrayInputStream(bs);
		// 创建一个ObjectInputStream 用于从指定的InputStream读回对象信息
		ObjectInputStream ois = new ObjectInputStream(is);
		// 返回对象的类、签名、以及这个类及其超类中所有非静态和非瞬时域的值
		String str1 = (String) ois.readObject();
		String str2 = (String) ois.readObject();
		System.out.println(str1 + str2);
	}

 

    f) 实现Externalizable接口,它继承自Serializable。在其序列化时会调用writeExternal方法,

          反序列化时通过调用无参构造器,然后调用readExternal进行对象的初始化。

public class Test implements Externalizable {

	private String str;
	private int i;

	// 反序列化时调用
	public Test() {
		System.out.println("无参构造器");
	}

	public Test(String str, int i) {
		System.out.println("构造器");
		this.str = str;
		this.i = i;
	}

	@Override
	public String toString() {
		return str + i;
	}

	// 序列化时调用
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		out.writeObject("writeExternal-");
		out.writeInt(1);
	}

	// 反序列化时调用
	@Override
	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		this.str = (String) in.readObject();
		this.i = in.readInt();
	}

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		// 初始化
		Test test = new Test("test", 0);
		// 序列化
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(outputStream);
		oos.writeObject(test);
		oos.close();
		// 反序列化
		ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(inputStream);
		Test te = (Test) ois.readObject();
		System.out.println(te);
		inputStream.close();
		ois.close();

	}
}

 

9
7
分享到:
评论

相关推荐

    Java IO NIO and NIO 2 无水印pdf

    Java IO NIO and NIO 2 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn...

    java IO NIO AIO.xmind

    涉及到java io, nio, aio相关知识点,学习过程中的一些总结,持续更新中,xmind 格式

    Java IO NIO and NIO 2 epub

    Java IO NIO and NIO 2 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

    Java IO_NIO

    Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的基础框架,它提供了丰富的类库,使得程序能够与各种设备、文件、网络进行数据交互。然而,传统的IO模型在处理大量并发连接时表现出效率较低的问题,...

    java io 与java nio区别

    ### Java IO 与 Java NIO 的区别 在深入探讨Java IO与Java NIO之间的区别之前,我们先简单回顾一下这两种I/O模型的基本概念。 #### 1. Java IO(Blocking IO) Java IO,也称为传统的阻塞式IO或同步阻塞式IO,是...

    Java IO与NIO文档

    Java IO与NIO是Java平台中用于处理输入输出操作的核心技术。它们在处理数据传输、文件操作、网络通信等方面起着至关重要的作用。本篇将深入探讨这两个领域,旨在帮助开发者更好地理解和应用这些概念。 首先,Java ...

    Java IO与NIO:深入理解与实践指南

    Java IO和NIO提供了两种不同的I/O处理方式,各有优势和适用场景。IO适用于简单的I/O操作,而NIO则适合于需要高性能和高并发的应用。了解这两种I/O处理方式的区别和特点,可以帮助开发者根据具体的应用需求选择合适的...

    Java IO,NIO and NIO.2 mobi

    java io nio nio2 java io的百科全书 mobi格式 需要kindle 软件

    JAVA IO and NIO

    Java IO (Input/Output) 和 NIO (Non-blocking Input/Output) 是Java平台中用于处理输入和输出操作的重要部分。这两种技术在实现客户端与服务器之间的通信时起着至关重要的作用。下面将详细介绍Java IO和NIO的特点、...

    java学习笔记1(java io/nio)

    java学习笔记1(java io/nio)设计模式

    Java.nio 与Java.io比较

    在探讨Java.nio与Java.io之间的比较时,我们首先需要理解这两个包在Java编程语言中的核心作用和它们各自的优势。Java.io和Java.nio是Java中处理输入/输出操作的两个主要框架,它们各自拥有独特的特性和应用场景。 #...

    JavaIO和NIO练习

    在"JavaIODemo"这个练习中,我们可能会看到以下内容: 1. 流的创建与使用:演示如何创建输入流和输出流对象,例如从文件读取数据并写入到另一个文件。 2. 缓冲技术:使用BufferedReader和BufferedWriter实现高效的...

    java nio与io性能测试

    Java NIO(New IO)是Java 1.4引入的一个新模块,它是对传统IO(Input/Output)的扩展,提供了更高效的数据传输方式。在Java IO中,数据的读写是通过流进行的,而NIO则引入了通道(Channel)和缓冲区(Buffer)的...

    Ioserver java Nio socket 框架

    Ioserver java Nio socket 框架 是个不错的NIO 通讯框架,本来想学习mina框架,看了看mina的源码太头痛,本人觉得看懂了Ioserver 再看mina的框架,想多的学习 java NIO 的也可以下载 看看,很值得学习啊!!!

    Java NIO与IO性能对比分析.pdf

    Java NIO(New IO,也称为Non-blocking IO)和传统的Java IO是Java编程语言中用于处理I/O操作的两种主要技术。随着互联网用户数量的激增,企业对应用程序的并发处理能力提出了更高的要求。为了解决传统Java IO模型在...

    java IO、NIO、AIO详解.docx

    Java IO、NIO、AIO 详解 Java IO、NIO、AIO 是 Java 语言中三种不同的输入/输出机制,分别对应着不同的编程模型和设计理念。在高并发环境中,选择合适的输入/输出机制非常重要,本文将对 Java IO、NIO、AIO 进行...

    JAVA IO-NIO 详解

    其中,NIO(New IO)是Java 1.4版本引入的一种新的IO处理方式,相较于传统的阻塞IO,NIO提供了更高的效率和灵活性。 #### 二、传统IO与NIO的区别 **1. 阻塞与非阻塞** - **传统IO**: 阻塞式操作,当进行读写操作...

    JavaNIO chm帮助文档

    Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六)...

Global site tag (gtag.js) - Google Analytics