Java基础~特殊RandomAccessFile “构造器”“写方法”“读方法”Chatset字符集 Charset类常用方法Buffer的使用 NIO和多路复用的区别 读写文件操作NIO

本文主要是介绍Java基础~特殊RandomAccessFile “构造器”“写方法”“读方法”Chatset字符集 Charset类常用方法Buffer的使用 NIO和多路复用的区别 读写文件操作NIO,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

特殊RandomAccessFile

RandomAccessFile构造器

 RandomAccessFile写方法

RandomAccessFile读方法

记录指针的特殊方法

 常见方法

NIO

 NIO基础

NIO和多路复用的区别  

IO模型

Buffer的使用 

 写文件操作

读文件操作

Buffer类的常用方法

 Channel类的常用方法

异常:

 写入数据

selector

 基本用法

 Chatset字符集

 Charset类


特殊RandomAccessFile

RandomAccessFile 不属于 IO 流,支持对文件的读取和写入随机访问
public class RandomAccessFile implements DataOutput, DataInput, Closeable
  • DataInput接口中定义了基本数据类型的读操作,例如readInt/readDouble
  • DataOutput接口定义了基本数据类型的写操作,例如writeInt/writeDouble
RandomAccessFile Java 输入 / 输出流体系中功能最丰富的文件内容访问类,既可以读取文件内容,也可以向文件输出数据。

RandomAccessFile构造器

RandomAccessFile 类在创建对象时,除了指定文件本身,还需要指定一个 mode 参数指定
RandomAccessFile 的访问模式,该参数有如下四个值:
  • r以只读方式打开指定文件。如果试图对该RandomAccessFile指定的文件执行写入方法则会抛出 IOException
  • rw以读取、写入方式打开指定文件。如果该文件不存在,则尝试创建文件
  • rws以读取、写入方式打开指定文件。相对于rw模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备,默认情形下(rw模式下),是使用buffer,只有cache满的或者使用 RandomAccessFile.close()关闭流的时候儿才真正的写到文件
  • rwdrws类似,只是仅对文件的内容同步更新到磁盘,而不修改文件的元数据

 RandomAccessFile写方法

 

RandomAccessFile raf=new RandomAccessFile("d:\\abc.data","rw"); 
raf.writeInt(1); 
raf.writeChars("yanjun"); 
raf.writeDouble(1234.0/567); 
raf.close();

RandomAccessFile读方法

RandomAccessFile raf=new RandomAccessFile("d:/abc.data","r");
int id=raf.readInt(); 
//String name=raf.readLine(); 
//byte[] bb=new byte[4]; 
//raf.readFully(bb); 
//String name=new String(bb); 
int len=raf.readInt(); 
StringBuilder sb=new StringBuilder(); 
for(int i=0;i<len;i++) sb.append(raf.readChar()); 
String name=sb.toString(); 
double salary=raf.readDouble();

 读取文件时如果到文件结尾是抛出异常EOFException,所以这里采用的是异常用于判断文件结束

典型应用:多线程下载和断点续传

记录指针的特殊方法

与普通的输入 / 输出流不同的是 : RandomAccessFile 支持跳到文件任意位置读写数据,
RandomAccessFile 对象包含一个记录指针,用以标识当前读写处的位置,当程序创建一个新的
RandomAccessFile 对象时,该对象的文件记录指针对于文件头(也就是 0 处),当读写 n 个字节后,文件记录指针将会向后移动n 个字节。除此之外, RandomAccessFile 可以自由移动该记录指针
RandomAccessFile包含两个方法来操作文件记录指针:文件指针是按照字节数进行统计,取值范围为[0,file.length()]
  • long getFilePointer():返回文件记录指针的当前位置
  • void seek(long pos):将文件记录指针定位到pos位置
  • skipByte(int step); 相对当前位置跳过step个字节
如果文件中间的内容需要进行修改,注意新内容中的字串和原始文件内容的长度应该一致,否则可能会导致修改数据后面的内容无法正常读取

 常见方法

void close() 关闭操作

int read(byte[] b)将内容读取到一个byte数组之中

byte readByte()读取一个字节

int readInt()从文件中读取整型数据… readDouble()8种简单类型

String readLine()读取一行数据

void writeBytes(String s)将一个字符串写入到文件之中,按字节的方式处理。writeChars

void writeInt(int v)将一个int型数据写入文件,长度为4位。…writeDouble8种类型

NIO

JDK1.4 开始 Java 引入了一系列改进的输入 / 输出处理的新功能,统称为 NIO ,即新 IO ,新增了许多用于处理输入输出的类,新IO 采用内存映射文件的方式处理输入输出,新 IO 将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件,这种方式进行输入输出比传统的输入输出快的多

 NIO基础

Channel 通道和 Buffer 缓冲是 NIO 中的两个核心对象
  • Chanel是对传统输入输出系统的模拟,通过map方法可以将一块数据映射到内存中
  • Buffer本质是一个数组,发送到Channel中的所有对象都必须先放到Buffer中,而从Channel中读取的数据必须先放到Buffer

NIO和多路复用的区别  

IO模型

  • 同步阻塞IOBlocking IO):即传统的IO模型
  • 同步非阻塞IONon-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置NONBLOCK。注意这里所说的NIO并非JavaNIONew IO)库
  • 多路复用IOIO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IOJava中的SelectorLinux中的epoll都是这种模型
  • 异步IOAsynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO

java NIO就是采用多路复用IO模式 

 在多路复用IO模型中,会有一个线程(Java中的Selector)不断去轮询多个socket的状态,只有当 socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用

Buffer的使用 

Buffer 是一个抽象类,主要作用是用于装入数据,然后输出数据
  • 最常见的子类ByteBuffer可以在底层字节数组上进行get/set操作
  • 其它基本数据类型都有对应的Buffer类:CharBuffer ShortBuffer IntBuffer LongBufferFloatBuffer DoubleBuffer

静态方法static XxxBuffer allocate(int capacity)创建一个容量为capacityXxxBuffer对象

Buffer 中有 3 个重要概念:容量 capacity 、界限 limit 和位置 position
  •  容量capacity表示该Buffer的最大数据容量,创建后则不能改变
  • 界限limit,位于limit后的数据既不可被读,也不可被写
  • 位置position用于指明下一个可以被读出的或者写入缓冲区的位置索引
  • 标记mark位置

 

Buffer position 0 limit capacity ,程序可以通过 put 方法向 Buffer 写入一些数据,每放入一些数据,Buffer position 响应的向后移动。

 写文件操作

String fileName = "nioFile"; 
try (FileOutputStream fos = new FileOutputStream(new File(fileName))) { FileChannel channel = fos.getChannel(); ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode("你好你好.."); int length = 0; while ((length = channel.write(byteBuffer)) != 0) { System.out.println("写入长度:" + length); 
} } catch (IOException e) { e.printStackTrace(); 
}

读文件操作

String fileName = "C:\IODemo\nioFile"; 
try (FileInputStream fis = new FileInputStream(new File(fileName)); FileChannel channel = fis.getChannel()) { int capacity = 100; ByteBuffer byteBuffer = ByteBuffer.allocate(capacity); int length = -1; while ((length = channel.read(byteBuffer)) != -1) { byteBuffer.clear(); byte[] array = byteBuffer.array(); System.out.write(array, 0, length); System.out.println(); } 
} catch (FileNotFoundException e) { e.printStackTrace(); 
}

Buffer类的常用方法

  • capacity():int返回Buffer的容量大小
  • hasRemaining():boolean判断是否还有元素可以进行处理
  • remaining():int返回当前位置和界限之间的元素个数
  • position():int返回当前操作的位置
  • mark():Buffer设置Buffer的标记位置,只能在0position之间做标记
  • reset():Buffer将位置position转到mark所在的位置
  • rewind():Buffer将位置position设置到0,取消设置的mark
  • put(obj)用于向Buffer中放入数据
  • get()用于从Buffer中取出数据

 // 创建对应的buffer对象,其中最大容积值为10

CharBuffer buffer = CharBuffer . allocate ( 10 );
System . out . println ( buffer . capacity ()); // 获取 buffer 的容积值
capacity=10,position=0,limit=10
System . out . println ( buffer . position ());
System . out . println ( buffer . limit ());
buffer . put ( ' ' );
System . out . println ( buffer . capacity ()); // 10
System . out . println ( buffer . position ()); // 1
System . out . println ( buffer . limit ()); // 10
String ss = " 中国人民解放军 " ;
for ( int i = 0 ; i < ss . length (); i ++ )
buffer . put ( ss . charAt ( i ));
buffer . flip (); // limit 设置到 position, 并且把 position 设置为 0 。相当于是将 buffer
没有数据的存储位置封印起来,从而避免读取时读到不合法的数据
System . out . println ( buffer . capacity ()); // 10
System . out . println ( buffer . position ()); // 0
System . out . println ( buffer . limit ()); //7
char cc = buffer . get (); // 获取 position 对应的字符
System . out . println ( cc ); //
System . out . println ( buffer . capacity ()); // 10
System . out . println ( buffer . position ()); // 1
System . out . println ( buffer . limit ()); //7
buffer . clear (); // 清空 buffer 中的数据,并重置 position limit
System . out . println ( buffer . capacity ()); // 10
System . out . println ( buffer . position ()); // 0
System . out . println ( buffer . limit ()); //10
ss = " 中国人民解放军 " ;
for ( int i = 0 ; i < ss . length (); i ++ )
buffer . put ( ss . charAt ( i ));
cc = buffer . get ( 2 ); // 按照下标位置获取对应的数据 , 并不会操作 position
System . out . println ( cc );
System . out . println ( buffer . position ()); //7

 Channel类的常用方法

Channel 可以直接将文件的部分或者全部直接映射成 Buffer
注意:不能直接访问 Channel 中的数据,包括读取、写入都不行。 Channel 只能与 Buffer 进行交互
  • 所有Channel不应该通过构造器来直接创建,而是通过传统的节点InputStreamOutputStreamgetChannel方法来返回对应的Channel
  • 常用的是FileInputStreamFileOutputStreamgetChannel()返回的FileChannel
Channel 中最常用的三个方法是 map() read() write()

 

File file = new File("T1.java"); 
FileChannel inChannel = new FileInputStream(file).getChannel(); 
ByteBuffer buffer = ByteBuffer.allocate(256); 
while (inChannel.read(buffer) != -1) {//多次读取数据的方式从文件中获取内容 buffer.flip(); //将没有数据的区域封印起来 Charset charset = Charset.forName("GBK");//使用GBK的字符集创建解码器 CharsetDecoder decoder = charset.newDecoder(); CharBuffer cb = decoder.decode(buffer);//使用解码器将ByteBuffer转换为CharBuffer                     System.out.println(cb); buffer.clear();//将position设置为0,为下一次读取数据做准备
}

异常:

java.nio.charset.MalformedInputException 一般是编码转换时由于编码字符集错误导致的,可以修改Charset 中编码字符集名称解决。例如 GBK UTF-8

map()方法将Channel对应的部分或全部数据映射成ByteBuffer  

File f = new File("T1.java"); 
FileChannel in = new FileInputStream(f).getChannel(); 
FileChannel out = new FileOutputStream("a.txt").getChannel(); 
MappedByteBuffer buffer = in.map(FileChannel.MapMode.READ_ONLY, 0, 
f.length());//参数1为执行映射时的模式,有只读、读写模式;参数2和3用于设置哪些数据执行映 射。可以将FileChannel中全部数据映射为ByteBuffer 
out.write(buffer); 
buffer.clear(); 
Charset charset = Charset.forName("GBK"); 
CharsetDecoder decoder = charset.newDecoder(); 
CharBuffer cb = decoder.decode(buffer); 
System.out.println(cb);

 写入数据

 File file = new File("data/a1.txt");
int len=(int)file.length();
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel channel = raf.getChannel();// 返回的channel是只读还是读写,取决于
RandomAccessFile文件对象的打开模式
ByteBuffer buffer = channel.map(MapMode.READ_ONLY, 0, len);//buffer支持可读,将
文件中的所有内容映射到buffer中
channel.position(len); //移动指针到内容末尾
channel.write(buffer); //重新写出buffer中的内容,实际上就是将文件内容拷贝

selector

Java NIO 核心组件中的一个,用于检查一个或多个 NIO Channel 通道的状态是否处于可读、可写。如此可以实现单线程管理多个channels 也就是可以管理多个网络链接。
使用 Selector 的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销
  • FileChannel不能切换为非阻塞模式,更准确的来说是因为FileChannel没有继承 SelectableChannel
  • 多用于网络应用编程中

 基本用法

1. Selector 的创建。通过调用 Selector.open() 方法创建一个 Selector 对象

 Selector selector = Selector.open();

 2. 注册ChannelSelector

 channel.configureBlocking(false);

SelectionKey key = channel.register(selector, Selectionkey.OP_READ);

Channel必须是非阻塞的。

3. 轮询方式获取选择器上的状态值

 while(selector.select()>0){

Iterator < SelectionKey > it = selector . selectedKeys (). iterator ();
...
}

 Chatset字符集

 所有文件在底层都是二进制文件,字符文件是系统将底层的二进制序列转换为字符,这里会涉及编码Encoder和解码Decoder

  • 将明文的字符序列转换为计算机理解的二进制序列称为编码
  • 将二进制序列转换为明文字符串称为解码

 Charset

availableCharsets()SortedMap<String,Charset> 获取当前JDK所支持的所有字符集

 *字符串别名

  • GBK简体中文
  • ISO-8859-1拉丁文
  • UTF-88UCS转换格式

 Charset c=Charset.forName("GBK");

Java7 新增 StandardCharsets 类,其中包含了 ISO_8859_1 UTF_8 UTF-16 等类变量,这些类变量代表了最常见的字符集对应的Charset 对象
  •  newDecoder():CharsetDecoder获取该编码字符集对应的解码
  • decode(ByteBuffer):CharBuffer方法可以将字节序列ByteBuffer转换为CharBuffer字符序列
  • newEncoder():CharsetEncoder获取该编码字符集对应的编码
  • encode(CharBuffer):ByteBuffer 方法可以将字符序列CharBuffer转换为ByteBuffer字节序列
Charset c1 = Charset.forName("GBK"); 
CharsetEncoder encoder = c1.newEncoder(); 
CharsetDecoder decoder = c1.newDecoder(); 
CharBuffer cb = CharBuffer.allocate(8); 
cb.put('孙'); 
cb.put('悟'); 
cb.put('空'); 
cb.flip(); 
ByteBuffer bb=encoder.encode(cb);//将CharBuffer转换为ByteBuffer 
for(int i=0;i<6;i++) { System.out.println(bb.get(i)+" "); 
}
System.out.println("===================="); 
System.out.println(decoder.decode(bb));//将byteBuffer转换为charBuffer

 

这篇关于Java基础~特殊RandomAccessFile “构造器”“写方法”“读方法”Chatset字符集 Charset类常用方法Buffer的使用 NIO和多路复用的区别 读写文件操作NIO的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/168872

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个