热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java编程思想学习笔记_5(IO流)

一、用DataInputStream读取字符可以使用available方法查看还有多少可供存取的字符.示例如下:publicclassTest1{publicsta

一、用DataInputStream读取字符

  可以使用available方法查看还有多少可供存取的字符.示例如下:

public class Test1 {
    public static void main(String[] args) throws IOException {
        DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
        while(in.available()!=0) {
            System.out.println((char)in.readByte());
        }
        in.close();
    }
}

二、新I/O

  1.JavaNIO和IO的主要区别:

    Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。 

      2.重要的接口:Channel接口和Buffer接口。速度的提高来自于所使用的结构更加接近于操作系统执行IO的方式:通道和缓冲器。我们和缓冲器(Buffer)交互,并把缓冲器派送到通道(Channel)。旧IO类中有三个类库可以用来产生FileChannel分别是FileInputStream、FileOutputStream、RandomAccessFile。而唯一与通道交互的缓冲器是ByteBuffer。下面用示例说明:例子产生可写的,可读的,可读可写的通道。

public class GetChannel {
    private static final int BSIZE=1024;
    public static void main(String[] args) throws Exception {
        FileChannel fc=new FileOutputStream("data.txt").getChannel();
        //写入操作
        fc.write(ByteBuffer.wrap("hello my".getBytes()));
        fc.close();
        fc=new RandomAccessFile("data.txt","rw").getChannel();
        fc.position(fc.size());
        fc.write(ByteBuffer.wrap("wife xyy".getBytes()));
        fc.close();
        //读取操作
        fc=new FileInputStream("data.txt").getChannel();
        ByteBuffer buff=ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip();    //一旦调用read来告知FileChannel向ByteBuffer存储字节,必须调用缓冲器上的flip,让它做好让别人读取的字节
        while(buff.hasRemaining()) {
            System.out.print((char)buff.get());
        }
    }
}

  将字节存放于ByteBuffer的方法之一是使用一种“put”方法对其直接填充或者使用wrap方法将已经产生的字节数组“包装”到ByteBuffer中,我们用RandomAccessFile再次将data.txt打开,这时可以利用position方法随意移动指针,完全读写操作。对于只读的操作,可以使用静态的allocate方法直接来分配ByteBuffer。注意在写完缓冲区需要读取的时候,需要调用filp方法,该方法将容器的最大可写入位置置为当前指针的位置,随后将当前指针位置置为0,为读取做准备。

  3.转换数据。缓冲器容纳的是普通的字符,为了将他们转化为字符,我们要么在输入的时候对其进行编码,要么将其从缓冲区输入时对其进行编码。可以使用Java.nio.CharSet类实现这些功能,示例如下:

public class BufferToText {
    private static final int BSIZE=1024;
    public static void main(String[] args) throws Exception{
        FileChannel fc=new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("some text".getBytes()));
        fc.close();
        fc=new FileInputStream("data2.txt").getChannel();
        ByteBuffer buff=ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip();
        System.out.println(buff.asCharBuffer());
        String encoding=System.getProperty("file.encoding");
        //第一种方法.通过Charset的forName方法对于ByteBuffer内包含的字节进行解码.
        System.out.println(encoding+":"+Charset.forName(encoding).decode(buff));
        //或者在输入的时候进行编码
        fc=new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("hello my love".getBytes("UTF-16BE")));
        fc.close();
        fc=new FileInputStream("data2.txt").getChannel();
        buff.clear();
        fc.read(buff);
        buff.flip();
        System.out.println(buff.asCharBuffer());
        //在写出的时候使用charbuffer
        fc=new FileOutputStream("data2.txt").getChannel();
        buff=ByteBuffer.allocate(24);
        buff.asCharBuffer().put("some text");
        fc.write(buff);
        fc.close();
        fc=new FileInputStream("data2.txt").getChannel();
        buff.clear();
        fc.read(buff);
        buff.flip();
        System.out.println(buff.asCharBuffer());
    }
}

  4、分散和聚集

  Java NIO开始支持分散/聚集操作,分散/聚集用于描述从Channel中读取或者写入到Channel的操作。 
  分散是指从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散”到多个Buffer中。 
  聚集是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集”后发送到Channel。

  分散的示例如下:

ByteBuffer header = ByteBuffer.allocate(128);  
ByteBuffer body   = ByteBuffer.allocate(1024);  
  
ByteBuffer[] bufferArray = { header, body };  
  
channel.read(bufferArray);  

  聚集的示例如下:

ByteBuffer header = ByteBuffer.allocate(128);  
ByteBuffer body   = ByteBuffer.allocate(1024);  
  
//write data into buffers  
  
ByteBuffer[] bufferArray = { header, body };  
  
channel.write(bufferArray);  

  5、通道之间的数据传输

  FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中,方法的第一个参数表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。 transferTo()方法将数据从FileChannel传输到其他的channel中,其余参数与transferfrom方法相同。下面用一个示例完成了文件的复制:

public class TransferTo {
    private static final int BSIZE=1024;
    public static void main(String[] args) throws IOException {
        FileChannel in=new FileInputStream("C:/a.txt").getChannel();
        FileChannel out=new FileOutputStream("C:/c.txt").getChannel();
        in.transferTo(0, in.size(), out);
    }
}

  6、内存映射文件

   内存映射文件允许我们创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,就可以假定它位于内存中,并且把它当一个很大的数组访问。

   FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.                  
  a. READ_ONLY,(只读): 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException.(MapMode.READ_ONLY)
   b. READ_WRITE(读/写): 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的。 (MapMode.READ_WRITE)
  c. PRIVATE(专用): 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本。 (MapMode.PRIVATE).下面是采用内存映射文件的一个简单示例,测试了内存映射文件和普通的ByteBuffer在写入数据时的速度对比:

public class ChannelTest1 {
    public static void main(String[] args) throws IOException {
        FileChannel fc=new RandomAccessFile("C:/cd.txt","rw").getChannel();
        CharBuffer cb=fc.map(FileChannel.MapMode.READ_WRITE,0, 1024).asCharBuffer();
        ByteBuffer buf=ByteBuffer.allocate(1024);
        CharBuffer cbuf=buf.asCharBuffer();
        long oldTime=System.nanoTime();
        for(int i=200;i<200;i++) {
            cb.put(""+i);
        }
        long lastTime=System.nanoTime();
        for(int i=200;i<200;i++) {
            cbuf.put(""+i);
        }
        fc.read(buf);
        long endTime=System.nanoTime();
        System.out.println(lastTime-oldTime);//821
        System.out.println(endTime-lastTime);//481950
    }
}

  实际上要写入的数据越多,这种写法的速度越快。

三、对象序列化

  1、序列化的控制:

       可以通过实现Externalizable接口,代替实现Serializable接口,来对序列化进行控制。该接口除了完成Serializable接口的功能以外,还增添了两个方法:writeExternal()和readExternal(),这两个方法会在序列化和反序列化还原的过程时被自动调用,以便执行特殊操作。

public class Test2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Blip blip=new Blip();
        blip.setStr("小狗");
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(blip);
        ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois=new ObjectInputStream(bis);
        Blip b=(Blip) ois.readObject();
        System.out.println(b);
    }
}
class Blip implements Externalizable {
    private String str;
    public Blip() {
        System.out.println("The constructor is execute");
    }
    
     public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
    

    @Override
    public String toString() {
        return "Blip [str=" + str + "]";
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("write is execute");
        out.writeObject(str);//对于变量初始化很有必要
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        str=(String) in.readObject();
        System.out.println("read is execute");
    }
    
}

 控制台打印:

The constructor is execute
write is execute
The constructor is execute
read is execute
Blip [str=小狗]

  恢复b的时候会调用默认构造器,因此与Serinable序列化不同,它必须要在writeExternal和readExernal内对其成员进行初始化,此外还要保证对象一定有默认构造器,否则会报错。

  2、transient关键字

  当一个成员变量为transient的时候,将不会自动保存到磁盘,自动序列化机制也不会尝试去恢复它。当对象恢复的时候,该成员变量值为null。


推荐阅读
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
author-avatar
mobiledu2502931987
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有