java nio关键字_JAVA中的NIO(二)

一、内存文件映射

内存文件映射允许我们创建和修改那些因为太大而不能放入内存中的文件。有了内存文件映射,我们就可以假定整个文件都在内存中,而且可以完全把文件当作数组来访问。

packagecom.dy.xidian;importjava.io.RandomAccessFile;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;public classLargeMappedFiles {static int length = 0x8FFFFFF;public static void main(String[] args) throwsException {

@SuppressWarnings("resource")

MappedByteBuffer out= new RandomAccessFile("test.dat", "rw")

.getChannel().map(FileChannel.MapMode.READ_WRITE,0, length);for (int i = 0; i < length; i++)

out.put((byte) 'x');

System.out.println("Finished writing");for (int i = length / 2; i < length / 2 + 6; i++)

System.out.print((char) out.get(i));

}

}

map中的0表示从文件的起始位置开始映射,映射的大小为length(128MB)。MappedByteBuffer是直接缓冲区(JVM对直接缓冲区的内容会直接进行IO操作,如果缓冲区是非直接的,JVM会先将用户缓冲区的数据copy到自己的缓冲区,在对自己的缓冲区进行IO操作),

所以MappedByteBuffer对大文件的操作速度要比普通的IO流快。MappedByteBuffer继承自ByteBuffer,所以我们对ByteBuffer的操作都适用于ByteBuffer。

二、对映射文件的部分加锁

文件映射通常应用于极大的文件。我们可能需要对这种巨大的文件进行部分加锁,以便其它进程可以修改文件中未被加锁的部分。例如:数据库就是这样吗,因此多个用户可以同时访问它

packagecom.dy.xidian;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.nio.ByteBuffer;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;importjava.nio.channels.FileLock;public classLockingMappedFiles {static final int LENGTH = 0X8FFFFFF;staticFileChannel fc;

@SuppressWarnings("resource")public static void main(String[] args) throwsException {

fc= new RandomAccessFile("test.dat", "rw").getChannel();

MappedByteBuffer out=fc

.map(FileChannel.MapMode.READ_WRITE,0, LENGTH);for (int i = 0; i < LENGTH; i++)

out.put((byte) 'x');new LockAndModify(out, 0, LENGTH / 3);new LockAndModify(out, LENGTH / 2, LENGTH / 2 + LENGTH / 4);

}private static class LockAndModify extendsThread {privateByteBuffer buff;private intstart, end;

LockAndModify(ByteBuffer buff,int start, intend) {super();this.start =start;this.end =end;this.buff =buff;

buff.limit(end);

buff.position(start);//创建一个新缓冲区标识对象//该对象的position=0,limit和capacity等于原缓冲区剩余字节数。

buff =buff.slice();

start();

}public voidrun() {try{//获取通道上的锁,指定加锁的起始位置和结束位置//将锁设置为独占锁

FileLock fl = fc.lock(start, end, false);

System.out.println("Locked: " + start + " to " +end);while (buff.position() < buff.limit() - 1)

buff.put((byte) (buff.get() + 1));

fl.release();

System.out.println("Released: " + start + " to " +end);

}catch(IOException e) {throw newRuntimeException(e);

}

}

}

}

3.GZIP的使用范例

packagecom.dy.xidian;importjava.io.BufferedOutputStream;importjava.io.BufferedReader;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.FileReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.util.zip.GZIPInputStream;importjava.util.zip.GZIPOutputStream;public classGZIPcompress {public static void main(String[] args) throwsIOException {if (args.length == 0) {

System.out.println("Usage: \n\tGZIPcompress file\n"

+ "\tUses GZIP compress to compress "

+ "the file to test.gz");

System.exit(1);

}

BufferedReader in= new BufferedReader(new FileReader(args[0]));

BufferedOutputStream out= newBufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test.gz")));

System.out.println("Writing file");intc;while ((c = in.read()) != -1) {

out.write(c);

}

in.close();

out.close();

System.out.println("Reading file");

BufferedReader in2= new BufferedReader(newInputStreamReader(new GZIPInputStream(new FileInputStream("test.gz"))));

String s;while ((s = in2.readLine()) != null)

System.out.println(s);

in2.close();

}

}

4.对象序列化

对象的序列化就是将那些实现了Seriallizable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。而且这种方式可以跨操作系统实现对象的传输,可以在window上将对象序列化,并通过网络传输给linux操作系统,然后在linux系统上进行对象的还原。对象的序列化可以实现轻量级持久性。"持久性"意味着一个对象的生存周期并不取决于程序是否正在执行,它可以存在于程序的调用之间。通过序列化将一个对象对象写入磁盘,然后在重新调用程序时恢复该对象。对象必须在程序中显示地序列化和反序列化还原。

序列化实例

对象的序列化首先要创建某些OutputStream对象,然后将其封装在一个ObjectOutpuStream对象中。这时,只需要调用writeObject()即可将对象序列化,并将其发送给OutputStream(对象的序列化是基于子节的,因要使用InputStream和OutputStream)。要反向进行该过程,需要将一个InputStream封装在ObjectInputStream内,然后调用readObject()。和往常一样,我们最后获得个是一个引用,它指向一个向上转型的Object(),所以必须向下转型才能设置他们。

packagecom.dy.xidian;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;importjava.util.Random;

@SuppressWarnings("serial")//Serializble是一个空接口,作为标识来表明该对象可以序列化

class Data implementsSerializable {private intn;public Data(intn) {super();this.n =n;

}publicString toString() {returnInteger.toString(n);

}

}

@SuppressWarnings("serial")public class Worm implementsSerializable {private static Random rand = new Random(47);private Data[] d = {new Data(rand.nextInt(10)), new Data(rand.nextInt(10)),new Data(rand.nextInt(10))};privateWorm next;private charc;public Worm(int i, charx) {

System.out.println("Worm constructor: " +i);

c=x;//递归创建对象,每个对象中的next指向下一个对象

if (--i > 0)

next= new Worm(i, (char) (x + 1));

}publicWorm() {

System.out.println("Default constructor");

}publicString toString() {

StringBuilder result= new StringBuilder(":");

result.append(c);

result.append("(");for(Data dat : d) {

result.append(dat);

}

result.append(")");//递归打印对象信息

if (next != null)

result.append(next);returnresult.toString();

}public static void main(String[] args) throwsException {

Worm w= new Worm(6, 'a');

System.out.println("w = " +w);//对基本流进行包装,将对象写到文件中

ObjectOutputStream out = new ObjectOutputStream(newFileOutputStream("worm.out"));

out.writeObject("Worm storage\n");

out.writeObject(w);

out.close();//从文件中读取对象

ObjectInputStream in = new ObjectInputStream(newFileInputStream("worm.out"));

String s=(String) in.readObject();

Worm w2=(Worm) in.readObject();if (w2 instanceofWorm)

System.out.println(s+ "w2 = " +w2);

in.close();//将对象序列化写到内存中

ByteArrayOutputStream bout = newByteArrayOutputStream();

ObjectOutputStream out2= newObjectOutputStream(bout);

out2.writeObject("Worm storage\n");

out2.writeObject(w);

out2.flush();

out2.close();//创建一个新的byteArray数组//bout存储区的数据复制到新数组中

ObjectInputStream in2 = new ObjectInputStream(newByteArrayInputStream(

bout.toByteArray()));

s=(String) in2.readObject();

Worm w3=(Worm) in2.readObject();

System.out.println(s+ "w3 = " +w3);

in2.close();

}

}

寻找类

反序列化在生成对象时不是凭空的,它需要参考该对象的类文件(class),然后通过类文件才能还原该对象(因为反序列化底层应用了反射机制)。所以类文件应该放在classpath路径下。

序列化的控制

有时我们考虑到安全问题,不希望一个的对象的所有部分都被序列化;或者是,一个对象被还原后,某子对象需要重新创建,从而不必将该对象序列化。在这种特殊情况下,可以通过实现Externalizable接口来替代Serializable接口。Extertnalizable接口继承了Serializable接口,同时增添了两个方法:writeExternal()和readExternal()。这个方法会在序列化和反序列化还原的过程中被自动调用,以便执行一些特殊的操作。注意: 一旦继承Externalizable接口,意味着对象的所有属性都不会再自动序列化。

packagecom.dy.xidian;importjava.io.Externalizable;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectInput;importjava.io.ObjectInputStream;importjava.io.ObjectOutput;importjava.io.ObjectOutputStream;public class Blip implementsExternalizable {private inti;privateString s;publicBlip() {

System.out.println("Blip Constructor");

}public Blip(String x, inta) {

System.out.println("Blip(String x, int a)");

s=x;

i=a;

}publicString toString() {return s +i;

}

@Overridepublic void writeExternal(ObjectOutput out) throwsIOException {

System.out.println("Blip.writeExternal");

out.writeObject(s);

out.writeInt(i);

}

@Overridepublic void readExternal(ObjectInput in) throwsIOException,

ClassNotFoundException {

System.out.println("Blip.readExternal");

s=(String) in.readObject();

i=in.readInt();

}public static void main(String[] args) throwsIOException,

ClassNotFoundException {

System.out.println("Constructing objects: ");

Blip b= new Blip("A String", 47);

System.out.println(b);

ObjectOutputStream o= new ObjectOutputStream(newFileOutputStream("Blip.out"));

System.out.println("Saving object");

o.writeObject(b);

o.close();

ObjectInputStream in= new ObjectInputStream(newFileInputStream("Blip.out"));

System.out.println("Recovering b:");

b=(Blip) in.readObject();

System.out.println(b);

in.close();

}

}

我们可以在writeExternal()和readExternal()来指定,将对象中那些属性进行序列化和反序列化。

Externalizable与Serializable的区别:Serializable是从存储的二进制数据中直接恢复出对象的,它不会调用构造器。而对于一个Externalizable对象,则默认的构造器都会被调用,然后再调用readExternal()。

transient(瞬时)关键字

该关键字使得我们在使用serializable时,可以让敏感属性不被序列化。

packagecom.dy.xidian;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;importjava.util.Date;importjava.util.concurrent.TimeUnit;public class Login implementsSerializable {/****/

private static final long serialVersionUID = 1L;private Date date = newDate();privateString username;private transientString password;publicLogin(String name, String pwd) {

username=name;

password=pwd;

}publicString toString() {return "logon info:\n username: " + username + "\n date: " +date+ "\n password: " +password;

}public static void main(String[] args) throwsIOException,

InterruptedException, ClassNotFoundException {

Login a= new Login("dy", "111111");

System.out.println("login a = " +a);

ObjectOutputStream o= new ObjectOutputStream(newFileOutputStream("Login.out"));

o.writeObject(a);

o.close();

TimeUnit.SECONDS.sleep(1);

ObjectInputStream in= new ObjectInputStream(newFileInputStream("Login.out"));

System.out.println("Recovering object at " + newDate());

a=(Login) in.readObject();

System.out.println("Login a = " +a);

in.close();

}

}

当我们将同一个对象在同一个流进行多次序列化后(对同一个对象多次调用writeObject方法),然后在同一流上对该对象多次反序列化后(多次调用readObject方法),那么反序列化后,内存中只会存在一个该对象,这很正常,因为在序列化时该对象也只有一个(即使我们序列化了多次)。但是,我们如果我们使用不同的流对该对象进行反序列话,那么内存会产生两个这样的对象。原因在于流之间是不会检测所要反序列化的对象是否存在于对方的流中。可以这样来记忆,每使用一个新的流进行反序列化时,就好像在new一个对象,使用同一流来反序列化同一种对象时,就好像在进行引用赋值。

packagecom.dy.xidian;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.io.ObjectOutputStream;importjava.io.Serializable;class Horse implementsSerializable{}class Animal implementsSerializable{privateHorse h;privateString name;publicAnimal(String nm, Horse h){

name=nm;this.h =h;

}publicString toString(){return name + super.toString() + this.h;

}

}public classMyWorld {public static void main(String[] args) throwsIOException {

Horse h= newHorse();

Animal n1= new Animal("a", h);

ByteArrayOutputStream buffer1= newByteArrayOutputStream();

ObjectOutputStream o1= newObjectOutputStream(buffer1);

o1.writeObject(n1);

o1.writeObject(n1);

ByteArrayOutputStream buffer2= newByteArrayOutputStream();

ObjectOutputStream o2= newObjectOutputStream(buffer1);

o1.writeObject(n1);

}

}

#

5.受限数据集存储

Preferences类提供了对于小的数据集的存储方式,它对于数据集的存储的方式和操作系统(比如在windows操作系统上会被存储到windows的注册表中)相关,我们不必了解具体的存储细节,主要关注一下该API如何使用

packagecn.xdysite;public classTest {public static voidmain(String[] args) {

Preferences prefs= Preferences.userNodeForPackage(Test.class);

prefs.put("name", "Bob");

prefs.putInt("Bob", 123456789);

prefs.putBoolean("single", true);int a = prefs.getInt("count", 0);

System.out.println(a);

prefs.putInt("count", ++a);

}

}

Preferences会根据传入的参数(必须是Class对象,这里是Test.class)创建一个存储节点,然后将数据存储的到节点,我们每运行一次上面的代码,会发现输出的值会比上一次大1.对于存储节点的区分是根据包来区分的,同一个包下的class对象会生成同一个存储节点,比如cn.xdysite下有个Test1和Test2类,那么我们传入Test1.class作为存储节点,可以用Test1.clTest2.class来取数据

7.参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值