读书人

java中IO操作拾掇 2

发布时间: 2012-10-13 11:38:17 作者: rapoo

java中IO操作整理 2

BufferedReader的小例子

注意: BufferedReader只能接受字符流的缓冲区,因为每一个中文需要占据两个字节,所以需要将System.in这个字节输入流变为字符输入流,采用:

    BufferedReader?buf?=?new?BufferedReader( ?????????????????new?InputStreamReader(System.in));?

下面给一个实例:

    import?java.io.BufferedReader; ?import?java.io.IOException; ?import?java.io.InputStreamReader; ??/** ??*?使用缓冲区从键盘上读入内容 ??*?*/?public?class?BufferedReaderDemo{ ?????public?static?void?main(String[]?args){ ?????????BufferedReader?buf?=?new?BufferedReader( ?????????????????new?InputStreamReader(System.in)); ?????????String?str?=?null; ?????????System.out.println("请输入内容"); ?????????try{ ?????????????str?=?buf.readLine(); ?????????}catch(IOException?e){ ?????????????e.printStackTrace(); ?????????} ?????????System.out.println("你输入的内容是:"?+?str); ?????} ?}?

运行结果:

请输入内容

dasdas

你输入的内容是:dasdas

Scanner类

其实我们比较常用的是采用Scanner类来进行数据输入,下面来给一个Scanner的例子吧

    import?java.util.Scanner; ??/** ??*?Scanner的小例子,从键盘读数据 ??*?*/?public?class?ScannerDemo{ ?????public?static?void?main(String[]?args){ ?????????Scanner?sca?=?new?Scanner(System.in); ?????????//?读一个整数 ?????????int?temp?=?sca.nextInt(); ?????????System.out.println(temp); ?????????//读取浮点数 ?????????float?flo=sca.nextFloat(); ?????????System.out.println(flo); ?????????//读取字符 ?????????//...等等的,都是一些太基础的,就不师范了。 ?????} ?}?

其实Scanner可以接受任何的输入流

下面给一个使用Scanner类从文件中读出内容

    import?java.io.File; ?import?java.io.FileNotFoundException; ?import?java.util.Scanner; ??/** ??*?Scanner的小例子,从文件中读内容 ??*?*/?public?class?ScannerDemo{ ?????public?static?void?main(String[]?args){ ??????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????Scanner?sca?=?null; ?????????try{ ?????????????sca?=?new?Scanner(file); ?????????}catch(FileNotFoundException?e){ ?????????????e.printStackTrace(); ?????????} ?????????String?str?=?sca.next(); ?????????System.out.println("从文件中读取的内容是:"?+?str); ?????} ?}?

【运行结果】:

从文件中读取的内容是:这些文件中的内容哦!

数据操作流DataOutputStream、DataInputStream类

    import?java.io.DataOutputStream; ?import?java.io.File; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ??public?class?DataOutputStreamDemo{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????char[]?ch?=?{?'A',?'B',?'C'?}; ?????????DataOutputStream?out?=?null; ?????????out?=?new?DataOutputStream(new?FileOutputStream(file)); ?????????for(char?temp?:?ch){ ?????????????out.writeChar(temp); ?????????} ?????????out.close(); ?????} ?}?

A B C

现在我们在上面例子的基础上,使用DataInputStream读出内容

    import?java.io.DataInputStream; ?import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.IOException; ??public?class?DataOutputStreamDemo{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????DataInputStream?input?=?new?DataInputStream(new?FileInputStream(file)); ?????????char[]?ch?=?new?char[10]; ?????????int?count?=?0; ?????????char?temp; ?????????while((temp?=?input.readChar())?!=?'C'){ ?????????????ch[count++]?=?temp; ?????????} ?????????System.out.println(ch); ?????} ?}?

【运行结果】:

AB

合并流 SequenceInputStream

SequenceInputStream主要用来将2个流合并在一起,比如将两个txt中的内容合并为另外一个txt。下面给出一个实例:

    import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.InputStream; ?import?java.io.OutputStream; ?import?java.io.SequenceInputStream; ??/** ??*?将两个文本文件合并为另外一个文本文件 ??*?*/?public?class?SequenceInputStreamDemo{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file1?=?new?File("d:"?+?File.separator?+?"hello1.txt"); ?????????File?file2?=?new?File("d:"?+?File.separator?+?"hello2.txt"); ?????????File?file3?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????InputStream?input1?=?new?FileInputStream(file1); ?????????InputStream?input2?=?new?FileInputStream(file2); ?????????OutputStream?output?=?new?FileOutputStream(file3); ?????????//?合并流 ?????????SequenceInputStream?sis?=?new?SequenceInputStream(input1,?input2); ?????????int?temp?=?0; ?????????while((temp?=?sis.read())?!=?-1){ ?????????????output.write(temp); ?????????} ?????????input1.close(); ?????????input2.close(); ?????????output.close(); ?????????sis.close(); ?????} ?}?

【运行结果】

结果会在hello.txt文件中包含hello1.txt和hello2.txt文件中的内容。

文件压缩 ZipOutputStream类

先举一个压缩单个文件的例子吧:

    import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.InputStream; ?import?java.util.zip.ZipEntry; ?import?java.util.zip.ZipOutputStream; ??public?class?ZipOutputStreamDemo1{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????File?zipFile?=?new?File("d:"?+?File.separator?+?"hello.zip"); ?????????InputStream?input?=?new?FileInputStream(file); ?????????ZipOutputStream?zipOut?=?new?ZipOutputStream(new?FileOutputStream( ?????????????????zipFile)); ?????????zipOut.putNextEntry(new?ZipEntry(file.getName())); ?????????//?设置注释 ?????????zipOut.setComment("hello"); ?????????int?temp?=?0; ?????????while((temp?=?input.read())?!=?-1){ ?????????????zipOut.write(temp); ?????????} ?????????input.close(); ?????????zipOut.close(); ?????} ?}?

【运行结果】

运行结果之前,我创建了一个hello.txt的文件,原本大小56个字节,但是压缩之后产生hello.zip之后,居然变成了175个字节,有点搞不懂。
不过结果肯定是正确的,我只是提出我的一个疑问而已。

java中IO操作拾掇 2

上面的这个例子测试的是压缩单个文件,下面的们来看看如何压缩多个文件。

    import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.InputStream; ?import?java.util.zip.ZipEntry; ?import?java.util.zip.ZipOutputStream; ??/** ??*?一次性压缩多个文件 ??*?*/?public?class?ZipOutputStreamDemo2{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????//?要被压缩的文件夹 ?????????File?file?=?new?File("d:"?+?File.separator?+?"temp"); ?????????File?zipFile?=?new?File("d:"?+?File.separator?+?"zipFile.zip"); ?????????InputStream?input?=?null; ?????????ZipOutputStream?zipOut?=?new?ZipOutputStream(new?FileOutputStream( ?????????????????zipFile)); ?????????zipOut.setComment("hello"); ?????????if(file.isDirectory()){ ?????????????File[]?files?=?file.listFiles(); ?????????????for(int?i?=?0;?i?<?files.length;?++i){ ?????????????????input?=?new?FileInputStream(files[i]); ?????????????????zipOut.putNextEntry(new?ZipEntry(file.getName() ?????????????????????????+?File.separator?+?files[i].getName())); ?????????????????int?temp?=?0; ?????????????????while((temp?=?input.read())?!=?-1){ ?????????????????????zipOut.write(temp); ?????????????????} ?????????????????input.close(); ?????????????} ?????????} ?????????zipOut.close(); ?????} ?}?

【运行结果】

先看看要被压缩的文件吧:

java中IO操作拾掇 2

接下来看看压缩之后的:

java中IO操作拾掇 2

大家自然想到,既然能压缩,自然能解压缩,在谈解压缩之前,我们会用到一个ZipFile类,先给一个这个例子吧。java中的每一个压缩文件都是可以使用ZipFile来进行表示的

    import?java.io.File; ?import?java.io.IOException; ?import?java.util.zip.ZipFile; ??/** ??*?ZipFile演示 ??*?*/?public?class?ZipFileDemo{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.zip"); ?????????ZipFile?zipFile?=?new?ZipFile(file); ?????????System.out.println("压缩文件的名称为:"?+?zipFile.getName()); ?????} ?}?

【运行结果】:

压缩文件的名称为:d:\hello.zip

现在我们呢是时候来看看如何加压缩文件了,和之前一样,先让我们来解压单个压缩文件(也就是压缩文件中只有一个文件的情况),我们采用前面的例子产生的压缩文件hello.zip

    import?java.io.File; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.InputStream; ?import?java.io.OutputStream; ?import?java.util.zip.ZipEntry; ?import?java.util.zip.ZipFile; ??/** ??*?解压缩文件(压缩文件中只有一个文件的情况) ??*?*/?public?class?ZipFileDemo2{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.zip"); ?????????File?outFile?=?new?File("d:"?+?File.separator?+?"unZipFile.txt"); ?????????ZipFile?zipFile?=?new?ZipFile(file); ?????????ZipEntry?entry?=?zipFile.getEntry("hello.txt"); ?????????InputStream?input?=?zipFile.getInputStream(entry); ?????????OutputStream?output?=?new?FileOutputStream(outFile); ?????????int?temp?=?0; ?????????while((temp?=?input.read())?!=?-1){ ?????????????output.write(temp); ?????????} ?????????input.close(); ?????????output.close(); ?????} ?}?

【运行结果】:
解压缩之前:

java中IO操作拾掇 2

这个压缩文件还是175字节
解压之后产生:

java中IO操作拾掇 2

又回到了56字节,表示郁闷。

现在让我们来解压一个压缩文件中包含多个文件的情况吧
ZipInputStream类

当我们需要解压缩多个文件的时候,ZipEntry就无法使用了,如果想操作更加复杂的压缩文件,我们就必须使用ZipInputStream类

    import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.InputStream; ?import?java.io.OutputStream; ?import?java.util.zip.ZipEntry; ?import?java.util.zip.ZipFile; ?import?java.util.zip.ZipInputStream; ??/** ??*?解压缩一个压缩文件中包含多个文件的情况 ??*?*/?public?class?ZipFileDemo3{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"zipFile.zip"); ?????????File?outFile?=?null; ?????????ZipFile?zipFile?=?new?ZipFile(file); ?????????ZipInputStream?zipInput?=?new?ZipInputStream(new?FileInputStream(file)); ?????????ZipEntry?entry?=?null; ?????????InputStream?input?=?null; ?????????OutputStream?output?=?null; ?????????while((entry?=?zipInput.getNextEntry())?!=?null){ ?????????????System.out.println("解压缩"?+?entry.getName()?+?"文件"); ?????????????outFile?=?new?File("d:"?+?File.separator?+?entry.getName()); ?????????????if(!outFile.getParentFile().exists()){ ?????????????????outFile.getParentFile().mkdir(); ?????????????} ?????????????if(!outFile.exists()){ ?????????????????outFile.createNewFile(); ?????????????} ?????????????input?=?zipFile.getInputStream(entry); ?????????????output?=?new?FileOutputStream(outFile); ?????????????int?temp?=?0; ?????????????while((temp?=?input.read())?!=?-1){ ?????????????????output.write(temp); ?????????????} ?????????????input.close(); ?????????????output.close(); ?????????} ?????} ?}?

【运行结果】:
被解压的文件:

java中IO操作拾掇 2

解压之后再D盘下会出现一个temp文件夹,里面内容:

java中IO操作拾掇 2

PushBackInputStream回退流

    import?java.io.ByteArrayInputStream; ?import?java.io.IOException; ?import?java.io.PushbackInputStream; ??/** ??*?回退流操作 ??*?*/?public?class?PushBackInputStreamDemo{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????String?str?=?"hello,rollenholt"; ?????????PushbackInputStream?push?=?null; ?????????ByteArrayInputStream?bat?=?null; ?????????bat?=?new?ByteArrayInputStream(str.getBytes()); ?????????push?=?new?PushbackInputStream(bat); ?????????int?temp?=?0; ?????????while((temp?=?push.read())?!=?-1){ ?????????????if(temp?==?','){ ?????????????????push.unread(temp); ?????????????????temp?=?push.read(); ?????????????????System.out.print("(回退"?+?(char)?temp?+?")?"); ?????????????}else{ ?????????????????System.out.print((char)?temp); ?????????????} ?????????} ?????} ?}?

【运行结果】:
hello(回退,) rollenholt

    /** ??*?取得本地的默认编码 ??*?*/?public?class?CharSetDemo{ ?????public?static?void?main(String[]?args){ ?????????System.out.println("系统默认编码为:"?+?System.getProperty("file.encoding")); ?????} ?}?

【运行结果】:

系统默认编码为:GBK

乱码的产生:

    import?java.io.File; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.OutputStream; ??/** ??*?乱码的产生 ??*?*/?public?class?CharSetDemo2{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????OutputStream?out?=?new?FileOutputStream(file); ?????????byte[]?bytes?=?"你好".getBytes("ISO8859-1"); ?????????out.write(bytes); ?????????out.close(); ?????} ?}?

【运行结果】:

??

一般情况下产生乱码,都是由于编码不一致的问题。

对象的序列化

对象序列化就是把一个对象变为二进制数据流的一种方法。

一个类要想被序列化,就行必须实现java.io.Serializable接口。虽然这个接口中没有任何方法,就如同之前的cloneable接口一样。实现了这个接口之后,就表示这个类具有被序列化的能力。

先让我们实现一个具有序列化能力的类吧:

    import?java.io.*; ?/** ??*?实现具有序列化能力的类 ??*?*/?public?class?SerializableDemo?implements?Serializable{ ?????public?SerializableDemo(){ ????????? ?????} ?????public?SerializableDemo(String?name,?int?age){ ?????????this.name=name; ?????????this.age=age; ?????} ?????@Override?????public?String?toString(){ ?????????return?"姓名:"+name+"??年龄:"+age; ?????} ?????private?String?name; ?????private?int?age; ?}?

这个类就具有实现序列化能力,

在继续将序列化之前,先将一下ObjectInputStream和ObjectOutputStream这两个类

先给一个ObjectOutputStream的例子吧:

    import?java.io.Serializable; ?import?java.io.File; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.ObjectOutputStream; ??/** ??*?实现具有序列化能力的类 ??*?*/?public?class?Person?implements?Serializable{ ?????public?Person(){ ??????} ??????public?Person(String?name,?int?age){ ?????????this.name?=?name; ?????????this.age?=?age; ?????} ??????@Override?????public?String?toString(){ ?????????return?"姓名:"?+?name?+?"??年龄:"?+?age; ?????} ??????private?String?name; ?????private?int?age; ?} ?/** ??*?示范ObjectOutputStream ??*?*/?public?class?ObjectOutputStreamDemo{ ?????public?static?void?main(String[]?args)?throws?IOException{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream( ?????????????????file)); ?????????oos.writeObject(new?Person("rollen",?20)); ?????????oos.close(); ?????} ?}?

【运行结果】:

当我们查看产生的hello.txt的时候,看到的是乱码,呵呵。因为是二进制文件。

虽然我们不能直接查看里面的内容,但是我们可以使用ObjectInputStream类查看:

    import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.ObjectInputStream; ??/** ??*?ObjectInputStream示范 ??*?*/?public?class?ObjectInputStreamDemo{ ?????public?static?void?main(String[]?args)?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectInputStream?input?=?new?ObjectInputStream(new?FileInputStream( ?????????????????file)); ?????????Object?obj?=?input.readObject(); ?????????input.close(); ?????????System.out.println(obj); ?????} ?}?

【运行结果】

姓名:rollen 年龄:20

到底序列化什么内容呢?

其实只有属性会被序列化。

Externalizable接口

被Serializable接口声明的类的对象的属性都将被序列化,但是如果想自定义序列化的内容的时候,就需要实现Externalizable接口。

当一个类要使用Externalizable这个接口的时候,这个类中必须要有一个无参的构造函数,如果没有的话,在构造的时候会产生异常,这是因为在反序列话的时候会默认调用无参的构造函数。

现在我们来演示一下序列化和反序列话:

    package?IO; ??import?java.io.Externalizable; ?import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.IOException; ?import?java.io.ObjectInput; ?import?java.io.ObjectInputStream; ?import?java.io.ObjectOutput; ?import?java.io.ObjectOutputStream; ??/** ??*?序列化和反序列化的操作 ??*?*/?public?class?ExternalizableDemo{ ?????public?static?void?main(String[]?args)?throws?Exception{ ?????????ser();?//?序列化 ?????????dser();?//?反序列话 ?????} ??????public?static?void?ser()?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectOutputStream?out?=?new?ObjectOutputStream(new?FileOutputStream( ?????????????????file)); ?????????out.writeObject(new?Person("rollen",?20)); ?????????out.close(); ?????} ??????public?static?void?dser()?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectInputStream?input?=?new?ObjectInputStream(new?FileInputStream( ?????????????????file)); ?????????Object?obj?=?input.readObject(); ?????????input.close(); ?????????System.out.println(obj); ?????} ?} ??class?Person?implements?Externalizable{ ?????public?Person(){ ??????} ??????public?Person(String?name,?int?age){ ?????????this.name?=?name; ?????????this.age?=?age; ?????} ??????@Override?????public?String?toString(){ ?????????return?"姓名:"?+?name?+?"??年龄:"?+?age; ?????} ??????//?复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用 ?????@Override?????public?void?writeExternal(ObjectOutput?out)?throws?IOException{ ?????????out.writeObject(this.name); ?????????out.writeInt(age); ?????} ??????//?复写这个方法,根据需要读取内容?反序列话的时候需要 ?????@Override?????public?void?readExternal(ObjectInput?in)?throws?IOException, ?????????????ClassNotFoundException{ ?????????this.name?=?(String)?in.readObject(); ?????????this.age?=?in.readInt(); ?????} ??????private?String?name; ?????private?int?age; ?}?

【运行结果】:

姓名:rollen 年龄:20

本例中,我们将全部的属性都保留了下来,

Serializable接口实现的操作其实是吧一个对象中的全部属性进行序列化,当然也可以使用我们上使用是Externalizable接口以实现部分属性的序列化,但是这样的操作比较麻烦,

当我们使用Serializable接口实现序列化操作的时候,如果一个对象的某一个属性不想被序列化保存下来,那么我们可以使用transient关键字进行说明:

下面举一个例子:

    package?IO; ??import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.ObjectInputStream; ?import?java.io.ObjectOutputStream; ?import?java.io.Serializable; ??/** ??*?序列化和反序列化的操作 ??*?*/?public?class?serDemo{ ?????public?static?void?main(String[]?args)?throws?Exception{ ?????????ser();?//?序列化 ?????????dser();?//?反序列话 ?????} ??????public?static?void?ser()?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectOutputStream?out?=?new?ObjectOutputStream(new?FileOutputStream( ?????????????????file)); ?????????out.writeObject(new?Person1("rollen",?20)); ?????????out.close(); ?????} ??????public?static?void?dser()?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectInputStream?input?=?new?ObjectInputStream(new?FileInputStream( ?????????????????file)); ?????????Object?obj?=?input.readObject(); ?????????input.close(); ?????????System.out.println(obj); ?????} ?} ??class?Person1?implements?Serializable{ ?????public?Person1(){ ??????} ??????public?Person1(String?name,?int?age){ ?????????this.name?=?name; ?????????this.age?=?age; ?????} ??????@Override?????public?String?toString(){ ?????????return?"姓名:"?+?name?+?"??年龄:"?+?age; ?????} ??????//?注意这里 ?????private?transient?String?name; ?????private?int?age; ?}?

【运行结果】:

姓名:null 年龄:20

最后在给一个序列化一组对象的例子吧:

    import?java.io.File; ?import?java.io.FileInputStream; ?import?java.io.FileOutputStream; ?import?java.io.ObjectInputStream; ?import?java.io.ObjectOutputStream; ?import?java.io.Serializable; ??/** ??*?序列化一组对象 ??*?*/?public?class?SerDemo1{ ?????public?static?void?main(String[]?args)?throws?Exception{ ?????????Student[]?stu?=?{?new?Student("hello",?20),?new?Student("world",?30), ?????????????????new?Student("rollen",?40)?}; ?????????ser(stu); ?????????Object[]?obj?=?dser(); ?????????for(int?i?=?0;?i?<?obj.length;?++i){ ?????????????Student?s?=?(Student)?obj[i]; ?????????????System.out.println(s); ?????????} ?????} ??????//?序列化 ?????public?static?void?ser(Object[]?obj)?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectOutputStream?out?=?new?ObjectOutputStream(new?FileOutputStream( ?????????????????file)); ?????????out.writeObject(obj); ?????????out.close(); ?????} ??????//?反序列化 ?????public?static?Object[]?dser()?throws?Exception{ ?????????File?file?=?new?File("d:"?+?File.separator?+?"hello.txt"); ?????????ObjectInputStream?input?=?new?ObjectInputStream(new?FileInputStream( ?????????????????file)); ?????????Object[]?obj?=?(Object[])?input.readObject(); ?????????input.close(); ?????????return?obj; ?????} ?} ??class?Student?implements?Serializable{ ?????public?Student(){ ??????} ??????public?Student(String?name,?int?age){ ?????????this.name?=?name; ?????????this.age?=?age; ?????} ??????@Override?????public?String?toString(){ ?????????return?"姓名:??"?+?name?+?"??年龄:"?+?age; ?????} ??????private?String?name; ?????private?int?age; ?}?

【运行结果】:

姓名: hello 年龄:20

姓名: world 年龄:30

姓名: rollen 年龄:40

读书人网 >编程

热点推荐