Java编程思想学习笔记_5(IO流)
一、用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);//
System.out.println(endTime-lastTime);//
}
}
实际上要写入的数据越多,这种写法的速度越快。
三、对象序列化
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。
Java编程思想学习笔记_5(IO流)的更多相关文章
- [Java编程思想-学习笔记]第3章 操作符
3.1 更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...
- Java编程思想 学习笔记1
一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...
- [Java编程思想-学习笔记]第1章 对象导论
1.1 抽象过程 Java是一门面向对象的语言,它的一个优点在于只针对待解问题抽象,而不用为具体的计算机结构而烦心,这使得Java有完美的移植性,也即Java的口号"Write Once, ...
- Java编程思想 学习笔记11
十一.持有对象 通常,程序总是根据运行时才知道的某些条件去创建新对象.在此之前,不会知道所需对象的数量,甚至不知道确切的类型. Java实用库还提供了一套相当完整的容器类来解决这个问题,其中基本的类 ...
- JAVA编程思想学习笔记6-chap16-18-斗之气6段
1.java.util.Arrays package com.chengjie; import java.util.Arrays; import java.util.List; public clas ...
- Java编程思想学习笔记——类型信息
前言 运行时类型信息(RTTI:Runtime Type Information)使得我们可以在程序运行时发现和使用类型信息. Java在运行时识别对象和类的信息的方式: (1)一种是RTTI,它假定 ...
- Java编程思想学习笔记——一切都是对象
前言 Java是基于C++的,但Java是一种更加纯粹的面向对象程序设计语言. C++和Java都是混合/杂合型语言.杂合型语言允许多种编程风格. 用引用操纵对象 每种编程语言都有自己操纵内存中元素的 ...
- Java编程思想学习笔记_6(并发)
一.从任务中产生返回值,Callable接口的使用 Callable是一种具有泛型类型参数的泛型,它的类型参数表示的是从方法call返回的值,而且必须使Executor.submit来去调用它.sub ...
- Java编程思想学习笔记_1(Java内存和垃圾回收)
1.Java中对象的存储数据的地方: 共有五个不同的地方可以存储数据. 1)寄存器.最快,因为位于处理器的内部,寄存器按需求分配,不能直接控制. 2)堆栈.位于通用RAM,通过堆栈指针可以从处理器那里 ...
随机推荐
- SlickGrid example 3: 可编辑单元
<button onclick="grid.setOptions({autoEdit:true})"> 设置自动辅助编辑下一个元素. 代码: <!DOCTYP ...
- poj1222 EXTENDED LIGHTS OUT
设输入矩阵为A,输出矩阵为B,目标矩阵为C(零矩阵). 方便起见,矩阵行列下标均从1开始. 考虑A矩阵元素a(i,j),B矩阵中与其相邻的元素 b(i,j),b(i - 1, j),b(i + 1,j ...
- JAVA基础知识之IO——对象序列化
对象序列化 Java对象序列化(Serialize)是指将Java对象写入IO流,反序列化(Deserilize)则是从IO流中恢复该Java对象. 对象序列化将程序运行时内存中的对象以字节码的方式保 ...
- MySQL常用操作总结
MySQL常用操作 前提条件:已安装MySQL. 学习目标:用一条sql语句写出A和B的剩余数量 AA表 BB表 以上为一道面试题,接下来由这道面试题来回顾一些数据库的基本操作. 登录MySQL su ...
- 局域网无法访问vmware虚拟机WEB服务器解决办法
环境:虚拟机服务器是centos,apache+php+mysql环境,但是局域网无法访问 1.本机能ping通虚拟机 2.虚拟机也能ping通本机 3.虚拟机能访问自己的web 4.本机无法访问虚拟 ...
- wpfのuri(让你完全明白wpf的图片加载方式以及URI写法)
绝对 pack WPF URI pack://application:,,,/是协议:“,,,”是“///”的变体 1.资源文件 — 本地程序集 Uri uri = new Uri("pac ...
- EasyUI 格式化DataGrid列
easyui DataGrid中格式化列,如果单价低于20,则使用定义列formatter为红色文本.格式化DataGrid列,我们应该设置formatter属性,这个属性是一个函数.格式化函数包括两 ...
- Winform容器标签 打印标签 对话框控件
一.容器标签 布局: Anchor:锁定位置,指定与窗口容器的边缘位置,会随着窗口大小的改变而改变: Dock:填充窗口的位置.一般与容器标签同时使用. 1.Panel:对控件进行分组.可以独立布局, ...
- 把int放在一个char数组里(用于处理每一位数字)
sprintf(): #include <stdio.h> void put_int_with_space(int v) { char str[50]; //定义一个足够大的 ...
- Python3基础 if-else实例 判断输入的数字是否为8
镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...