Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 246|回复: 0

[默认分类] 2.熟悉Java基本类库系列——Java IO 类库

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-15 16:13:56 | 显示全部楼层 |阅读模式
    java中常用的IO操作基本上可以分为四大部分,分别是:File类操作、RandomAccessFile类操作、字节流操作、字符流操作。只要熟练掌握了本文中所列举的所有例子,基本上对于Java的IO流操作就可以说是掌握了。下面将以JUnit测试用例的方式,用一个个例子的方式列出这四大部分中常用的操作例子。一、File类操作File类操作定义了最基本的、与操作系统的稳健系统相关的操作,可以对文件夹、文件进行一系列的操作。 1、常用的一些用法
    1.        //1.两个常量
    2. @Test public void twoConstant(){
    3. //输出: "/"  ":"
    4. System.out.println(File.separator);
    5. System.out.println(File.pathSeparator);
    6. }
    7. //2.创建新文件
    8. @Test public void createFile(){
    9. File f = new File("hello");
    10. try{
    11. f.createNewFile();
    12. System.out.println("创建了文件:" + f.getAbsolutePath());
    13. }catch(Exception e){
    14. e.printStackTrace();
    15. }
    16. }
    17. //3.创建一个文件夹
    18. @Test public void createFolder(){
    19. try{
    20. File file = new File("HelloFolder");
    21. //当一个目录下既没有该名字对应的目录和文件时,才能建立该文件夹
    22. if(!file.isDirectory() && !file.isFile()){
    23. file.mkdir();
    24. //file.mkdirs(); //如果上级目录不存在,那么一并创建上级目录
    25. }else{
    26. System.out.println("已存在该名称的文件或文件夹");
    27. }
    28. }catch(Exception e){
    29. e.printStackTrace();
    30. }
    31. }
    32. //4.删除一个文件
    33. @Test public void deleteFile(){
    34. try{
    35. File file = new File("hello");
    36. if(file.exists()){
    37. file.delete();
    38. }else{
    39. System.out.println("文件不存在");
    40. }
    41. }catch(Exception e){
    42. e.printStackTrace();
    43. }
    44. }
    45. //5.删除一个文件夹(与删除文件一样)
    46. @Test public void deleteFolder(){
    47. try{
    48. File file = new File("HelloFolder");
    49. if(file.exists()){
    50. file.delete();
    51. }else{
    52. System.out.println("该文件夹不存在");
    53. }
    54. }catch(Exception e){
    55. e.printStackTrace();
    56. }
    57. }
    58. //6.获取指定目录下所有文件的文件名(包括隐藏文件和文件夹)
    59. @Test public void getAllFileName(){
    60. try{
    61. File folder = new File(".");  //当前目录
    62. String[] fileStrs = folder.list();
    63. for(String str : fileStrs){
    64. System.out.print(str + " ");
    65. }
    66. }catch(Exception e){
    67. e.printStackTrace();
    68. }
    69. }
    70. //7.获取指定目录下所有文件的路径
    71. @Test public void getAllFilePath(){
    72. try{
    73. File folder = new File(".");  //当前目录
    74. File[] files = folder.listFiles();
    75. for(File file : files){
    76. System.out.println(file.getCanonicalPath());
    77. }
    78. }catch(Exception e){
    79. e.printStackTrace();
    80. }
    81. }   
    复制代码
    2、打印指定目录下的所有文件(递归调用)
    1. package com.chanshuyi.io;
    2. /**
    3. * 列出指定目录的全部内容
    4. * */
    5. import java.io.*;
    6. class ListAllFile{
    7.     public static void main(String[] args) {
    8.         File f = new File(".");
    9.         print(f);
    10.     }
    11.    
    12.     //递归打印
    13.     public static void print(File f){
    14.     if(f != null){
    15.     if(f.isDirectory()){
    16.     File[] fileArray = f.listFiles();
    17.     if(fileArray != null){
    18.     for(int i = 0; i < fileArray.length; i++){
    19.     print(fileArray[i]);
    20.     }
    21.     }
    22.     }else{
    23.     System.out.println(f);
    24.     }
    25.     }
    26.     }
    27. }
    复制代码
    二、RandomAccessFile类操作RandomAccessFile类可以对文件进行随机访问,比如可以指定读写指针到某一个字节处,也可以读写指针指定跳过指定字节数。简单地说,RandomAccessFile类提供了许多方法,使得我们可以对文件进行更加细致的读写操作。
    1. //8.随机读写文件类
    2. @Test public void operateRandom(){
    3. try{
    4. //1.跳过两个字节读取文件内容
    5. //文件内容是:Hello, this is demo File.
    6. RandomAccessFile randomRW = new RandomAccessFile(new File("demo.txt"), "rw");
    7. randomRW.skipBytes(2);  //跳过两个字节,即跳过了"he"两个英文字符(一个英文字符占用1个字节)
    8. byte b[] = new byte[100];
    9. int length = randomRW.read(b);
    10. System.out.println("总共读取了" + length + "个字节,读取的内容是:" + new String(b));
    11. //总共读取了23个字节,读取的内容是:llo, this is demo File.
    12. //2.将读写指针跳回文件头重新读取
    13. randomRW.seek(0);
    14. length = randomRW.read(b);
    15. System.out.println("总共读取了" + length + "个字节,读取的内容是:" + new String(b));
    16. //总共读取了25个字节,读取的内容是:Hello, this is demo File.
    17. //3.获取读写指针所在地址
    18. long pointer = randomRW.getFilePointer();
    19. System.out.println("文件指针地址:" + pointer);  //文件指针地址:25
    20. randomRW.seek(2);
    21. pointer = randomRW.getFilePointer();
    22. System.out.println("文件指针地址:" + pointer);//文件指针地址:2
    23. randomRW.seek(77);
    24. pointer = randomRW.getFilePointer();
    25. System.out.println("文件指针地址:" + pointer);//文件指针地址:77
    26. randomRW.close();
    27. }catch(Exception e){
    28. e.printStackTrace();
    29. }
    复制代码
    三、字节流读写FileInputStream / FileOutputStream - 实现了对文件的读写操作ObjectInpuStream / ObjectOutputStream - 实现了对序列化对象的读写操作ByteArrayInputStream / ByteArrayOutputStream - 实现了对字节数组的读写操作PipedInputStream / PipedOutputStream - 实现不同线程之间的通信SequenceInputStream - 实现不同输入流的合并(此对象没有对应的OutputStream类)BufferedInputStream / BufferedOutputStream - 实现读写缓存1、字节流读取 - byte(表示读取的数据类型是byte或byte[])
    1. //15.字节流读取 - byte
    2. @Test public void readByte(){
    3. try{
    4. File file = new File("hello.txt");
    5. InputStream fos = new FileInputStream(file);
    6. byte[] bytes = new byte[fos.available()];
    7. fos.read(bytes);
    8. String str = new String(bytes);
    9. System.out.println("文件内容是:\n" + str);
    10. fos.close();
    11. }catch(Exception e){
    12. e.printStackTrace();
    13. }
    14. }
    复制代码
    2、字节流读取(缓存) - byte
    1. //字节流读取(缓存) - byte
    2. @Test public void writeByteWithBuffere(){
    3. try{
    4. File file = new File("hello1.txt");
    5. OutputStream fos = new FileOutputStream(file);
    6. BufferedOutputStream out = new BufferedOutputStream(fos);
    7. out.write("你好\n".getBytes());
    8. out.write("吃饭了么!".getBytes());
    9. out.flush();
    10. fos.close();
    11. }catch(Exception e){
    12. e.printStackTrace();
    13. }
    14. }
    复制代码
    3、字节流写入 - byte
    1. //17.字节流写入 - byte
    2. @Test public void writeByte(){
    3. try{
    4. File file = new File("hello.txt");
    5. OutputStream fos = new FileOutputStream(file);
    6. fos.write("Hello Mac.\n你好,Mac.".getBytes());
    7. fos.close();
    8. }catch(Exception e){
    9. e.printStackTrace();
    10. }
    11. }
    复制代码
    4、字节流写入(缓存) - byte
    1. //18.字节流写入(缓存) - byte
    2. @Test public void writeByteWithBuffer(){
    3. try{
    4. File file = new File("hello.txt");
    5. OutputStream fos = new FileOutputStream(file);
    6. BufferedOutputStream bos = new BufferedOutputStream(fos);
    7. bos.write("Hello Mac.\n你好,Mac.".getBytes());
    8. bos.close();
    9. fos.close();
    10. }catch(Exception e){
    11. e.printStackTrace();
    12. }
    13. }
    复制代码
    如果你仔细敲过上面4个例子的代码你会发现,其实好像字节流的读取和写入,好像加了缓存和没加缓存,它们的代码好像都差不多啊,至少再写入数据的时候是一样的。而字符流的读取在加了缓存层之后,至少还能直接读取整行数据,字符流的写入加了缓存之后,可以写入换行符。那字节流的缓存究竟有什么必要性呢?确实,从代码以及其方法上看,其实他们并没有什么区别,但是从官方的API文档来看,缓存最重要的一个地方就是减少程序对于磁盘的IO次数。加了缓存的程序再读取的时候会一次性读取很多个字节,之后提供给程序使用,但如果你不加缓存,那么程序就只会读取代码中指定的字节数。这在你一个字节一个字节从文件中读取数据的时候,其差别就凸现出来了。如果你没有使用缓存进行数据读取,那么你每读一个字节的数据,程序就去磁盘读取一次文件,这样会造成磁盘的频繁IO读取,减少磁盘的寿命。5、ObjectInputStream / ObjectOutputStream - 序列化一个对象要被序列化的POJO对象:
    1. package com.chanshuyi.io.po;
    2. import java.io.Serializable;
    3. public class Student implements Serializable{
    4. /**
    5. * 序列化ID
    6. */
    7. private static final long serialVersionUID = 7288449352920655248L;
    8. private String name;
    9. private int age;
    10. private String phone;
    11. public Student(){
    12. }
    13. public Student(String name, int age, String phone){
    14. this.name = name;
    15. this.age = age;
    16. this.phone = phone;
    17. }
    18. public String getName() {
    19. return name;
    20. }
    21. public void setName(String name) {
    22. this.name = name;
    23. }
    24. public int getAge() {
    25. return age;
    26. }
    27. public void setAge(int age) {
    28. this.age = age;
    29. }
    30. public String getPhone() {
    31. return phone;
    32. }
    33. public void setPhone(String phone) {
    34. this.phone = phone;
    35. }
    36. public String toString(){
    37. return name + "," + age + "," + phone;
    38. }
    39. }
    复制代码
    被序列化的POJO对象需要实现Serializable接口。序列化对象方法:
    1. //20.ObjectOutputStream - 序列化对象 - 将对象属性序列化保存
    2. @Test public void serialized(){
    3. try{
    4. Student std = new Student("Tommy", 13, "18923923876");
    5. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("StudentObject.obj"));
    6. oos.writeObject(std);
    7. oos.close();
    8. }catch(Exception e){
    9. e.printStackTrace();
    10. }
    11. }
    复制代码
    反序列化对象方法:
    1. //21.ObjectInputStream - 反序列化对象 - 读取序列化后的对象
    2. @Test public void deSerialized(){
    3. try{
    4. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("StudentObject.obj"));
    5. Student std = (Student)ois.readObject();
    6. System.out.println(std);
    7. ois.close();
    8. }catch(Exception e){
    9. e.printStackTrace();
    10. }
    11. }
    复制代码
    6、ByteArrayInputStream / ByteArrayOutputStream - 操作内存字节数据
    1. //19.ByteArrayInputStream - 内存操作流 - 将内存数据转化为流
    2. @Test public void random2Stream(){
    3. try{
    4. String str = "你好";
    5. ByteArrayInputStream input = new ByteArrayInputStream(str.getBytes());
    6. ByteArrayOutputStream output = new ByteArrayOutputStream();
    7. int temp = 0;
    8. while((temp = input.read()) != (-1)){
    9. char ch = (char)temp;
    10. output.write(Character.toLowerCase(ch));
    11. }
    12. String outputStr = output.toString();
    13. input.close();
    14. output.close();
    15. System.out.println(outputStr);
    16. }catch(Exception e){
    17. e.printStackTrace();
    18. }
    19. }
    复制代码
    7、PipedInputStream / PipedOutputStream - 实现进程间的管道通信接收者:
    1. package com.chanshuyi.io.pineStream;
    2. import java.io.PipedInputStream;
    3. /**
    4. * 管道流 - 接收者
    5. * @author yurongchan
    6. *
    7. */
    8. public class Receiver implements Runnable{
    9. private PipedInputStream in = null;
    10. public Receiver(){
    11. in = new PipedInputStream();
    12. }
    13. public PipedInputStream getIn(){
    14. return this.in;
    15. }
    16. public void run(){
    17. byte[] b = new byte[1000];
    18. int length = 0;
    19. try{
    20. length = this.in.read(b);
    21. }catch(Exception e){
    22. e.printStackTrace();
    23. }
    24. System.out.println("接收到的消息:" + new String(b, 0, length));
    25. }
    26. }
    复制代码
    发送者:
    1. package com.chanshuyi.io.pineStream;
    2. import java.io.PipedOutputStream;
    3. /**
    4. * 管道流 - 发送者
    5. * @author yurongchan
    6. *
    7. */
    8. public class Send implements Runnable{
    9. private PipedOutputStream out = null;
    10. public Send(){
    11. out = new PipedOutputStream();
    12. }
    13. public PipedOutputStream getOut(){
    14. return this.out;
    15. }
    16. public void run(){
    17. String msg = "Hello, I"m outputer.\n你好,我是发送者。";
    18. try{
    19. out.write(msg.getBytes());
    20. out.close();
    21. }catch(Exception e){
    22. e.printStackTrace();
    23. }
    24. }
    25. }
    复制代码
    测试方法:
    1. //22.PipedInputStream - 在不同线程之间进行通信
    2. @Test public void pipeContact(){
    3. try{
    4. Send send = new Send();
    5. Receiver receiver = new Receiver();
    6. try{
    7. send.getOut().connect(receiver.getIn());
    8. }catch(Exception e){
    9. e.printStackTrace();
    10. }
    11. new Thread(send).start();
    12. new Thread(receiver).start();
    13. }catch(Exception e){
    14. e.printStackTrace();
    15. }
    16. }
    复制代码
    8、SequenceInputStream - 合并输入流
    1. //23.SequenceInputStream - 合并几个输入流
    2. @Test public void sequenceInputStream(){
    3. try{
    4. InputStream is1 = new FileInputStream(new File("sequence1.txt"));
    5. InputStream is2 = new FileInputStream(new File("sequence2.txt"));
    6. OutputStream os = new FileOutputStream(new File("sequence3.txt"));
    7. SequenceInputStream sis = new SequenceInputStream(is1, is2);
    8. int temp = 0;
    9. while((temp = sis.read()) != -1){
    10. os.write(temp);
    11. }
    12. sis.close();
    13. is1.close();
    14. is2.close();
    15. os.close();
    16. }catch(Exception e){
    17. e.printStackTrace();
    18. }
    19. }
    复制代码
    之后打开sequence3.txt会发现,1、2文本中的内容都到了sequence3.txt中了。四、字符流读写字符流的读写实际上还是基于字节流实现的,而且数组存储时更多是以字节为单位存储,因此更多时候还是使用字节流进行读写操作。因此对于字符流的读写,我们只需要掌握常用的几个操作即可。InputStreamReader / OutputStreamWriter - 实现字符流的读写BufferedReader / BufferedWriter - 实现字符流的缓存层FileReader / FileWriter - 字符流的工具类1、字符流读取 - char(表示读取的数据类型是char或char[])
    1. //9.字符流读取 - char
    2. @Test public void writeChar(){
    3. try{
    4.     InputStreamReader reader = new InputStreamReader(new FileInputStream("OutputStreamWriter.txt"));
    5.     char[] chars = new char[1000];
    6.     int length = reader.read(chars);
    7.     System.out.println("一共读取了" + length + "个字符,内容是:" + new String(chars));
    8.     reader.close();
    9.   }catch(Exception e){
    10.     e.printStackTrace();
    11.   }
    12. }
    复制代码
    2、字符流读取(缓存) - char
    1. //10.字符流读取(缓存)
    2. @Test public void writeCharWithBuffer(){
    3. try{
    4. InputStreamReader isr = new InputStreamReader(new FileInputStream("BufferedWriter.txt"));
    5. BufferedReader reader = new BufferedReader(isr);
    6. String str = "";
    7. while((str = reader.readLine()) != null && str.length() != 0){
    8. System.out.println(str);
    9. }
    10. reader.close();
    11. }catch(Exception e){
    12. e.printStackTrace();
    13. }
    14. }
    复制代码
    3、字符流写入 - char / char[] / String
    1. //11.字符流写入
    2. @Test public void readChar(){
    3. try{
    4.   OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("OutputStreamWriter.txt"));
    5.   writer.write("AllFileTest.fileReadUtil -> 字符流写入文件");
    6.   writer.close();
    7. }catch(Exception e){
    8.   e.printStackTrace();
    9. }
    10. }
    复制代码
    4、字符流的写入(缓存)- char/ String
    1. //12.字符流写入(缓存)
    2. @Test public void readCharWithBuffer(){
    3. try{
    4. OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("BufferedWriter.txt"));
    5. BufferedWriter writer = new BufferedWriter(osw);
    6. writer.write("AllFileTest.fileReadUtil -> 字符流写入文件");
    7. writer.newLine();//换行
    8. writer.write("第二行");
    9. writer.close();
    10. }catch(Exception e){
    11. e.printStackTrace();
    12.     }
    13. }
    复制代码
    总结一下上面四种方式的字符流写入写出,我们会发现两个规律,一个是读写规律,一个是缓存层的规律:&middot; 读写规律。字符流的读取,其读取的数据都是char(字符型)的单个或者数组。而字符流的写入除了可以写入单个或多个char类型的字符歪,还可以直接写入String(字符串)类型。&middot; 缓存层规律。字符流的读写,增加了缓存层之后的一个明显区别就是:加了缓存层(Buffer)之后,字符流读取可以实现整行读取(readLine),而字符流写入可以实现写入换行符(writeLine)。5、文件读取工具类
    1. //13.FileReader - 文件读取工具类(这是加了缓存的。但也可以不加缓存)
    2. @Test public void fileReadUtil(){
    3.     try{
    4. FileReader fr = new FileReader(new File("demo.txt"));
    5. BufferedReader reader = new BufferedReader(fr);
    6. String str = "";
    7. while((str = reader.readLine()) != null && str.length() != 0){
    8. System.out.println(str);
    9. }
    10. reader.close();
    11. }catch(Exception e){
    12. e.printStackTrace();
    13. }
    14. }
    复制代码
    将这个例子与上面的第2个例子,即加了缓存的字符流读取例子相比,你会发现其实这两个例子的区别就只是声明FileReader、InputStreamReader的区别而已。声明FileReader只需要再加上File类型参数即可,而声明InputStreamReader则需要再加上一个FileInputStream类,之后才能跟上File类型的参数。因此,我们才说FileReader是一个文件读取工具类。6、文件写入工具类
    1. //14.FileWriter - 文件写入工具类(这是加了缓存的。但也可以不加缓存)
    2. @Test public void fileWriteUtil(){
    3. try{
    4. FileWriter fw = new FileWriter(new File("FileWriteUtil1.txt"));
    5. BufferedWriter writer = new BufferedWriter(fw);
    6. writer.write("HelloMan1");
    7. writer.newLine();
    8. writer.write("HelloMan2");
    9. writer.close();
    10. }catch(Exception e){
    11. e.printStackTrace();
    12. }
    13. }
    复制代码
    同样的,其实FileWriter与OutputStreamWriter也只是声明上的区别而已。五、其他这里会收集一些不怎么常用,但是有时也会用到的例子,遇到的时候可以快速的查询到。1、追加新的内容
    1. //9.字节流 - 追加新内容
    2. //无论是字节流还是字符流,要追加新的内容都是再FileOutputStream中指定第二个参数为true
    3. @Test public void appendFile(){
    4. try{
    5. File file = new File("hello.txt");
    6. OutputStream fos = new FileOutputStream(file, true);
    7. String str = "\n这是新增加的内容";
    8. fos.write(str.getBytes());
    9. fos.close();
    10. }catch(Exception e){
    11. e.printStackTrace();
    12. }
    13. }
    复制代码
    2、模拟打印流输出数据
    1. //18.打印流 - 模拟打印的方式输出数据
    2. @Test public void printStream(){
    3. try{
    4. PrintStream print = new PrintStream(new FileOutputStream(new File("PrintStream.txt")));
    5. print.println(true);
    6. print.println("您好,我是打印输出流");
    7. print.printf("名字:%s.年龄:%d", "Tom", 32); //格式化输出
    8. print.close();
    9. //这里的数据要再PrintStream.txt文件中才能看到
    10. }catch(Exception e){
    11. e.printStackTrace();
    12. }
    13. }
    复制代码
    3、使用OutputStream向屏幕输出内容
    1. //19.使用OutputStream向屏幕输出内容
    2. @Test public void systemOutStream(){
    3. try{
    4. OutputStream out = System.out;
    5. out.write("你好".getBytes());
    6. out.close();
    7. }catch(Exception e){
    8. e.printStackTrace();
    9. }
    10. }
    复制代码
    4、标准输出重定向
    1. //20.标准输出重定向
    2. @Test public void redirectOutput(){
    3. try{
    4. System.out.println("Print in the Screen. 你好");
    5. System.setOut(new PrintStream(new FileOutputStream(new File("RedirectOutput.txt"))));
    6. //下面的输出都将重定向到文件中
    7. System.out.println("=== 重定向后的输出 ===");
    8. System.out.println("Hello, Eclipse in Mac.");
    9. }catch(Exception e){
    10. e.printStackTrace();
    11. }
    12. }
    复制代码
    5、标准输入重定向
    1. //21.标准输入重定向
    2. @Test public void redirectInput(){
    3. try{
    4. File file = new File("RedirectOutput.txt");
    5. if(!file.exists()){
    6. System.out.println("文件不存在!");
    7. return;
    8. }else{
    9. System.setIn(new FileInputStream(file));
    10. byte b[] = new byte[1000];
    11. int length = System.in.read(b);
    12. System.out.println("读入的内容为:" + new String(b, 0, length));
    13. }
    14. }catch(Exception e){
    15. e.printStackTrace();
    16. }
    17. }
    复制代码
    6、错误输出重定向
    1. //22.错误输出重定向
    2. @Test public void redirectErrOutput(){
    3. try{
    4. System.err.println("Print in the Screen. 你好");
    5. System.setErr(new PrintStream(new FileOutputStream(new File("RedirectErrOutput.txt"))));
    6. //下面的输出都将重定向到文件中
    7. System.err.println("=== 重定向后的错误输出 ===");
    8. System.err.println("Hello, Eclipse in Mac.");
    9. }catch(Exception e){
    10. e.printStackTrace();
    11. }
    12. }
    复制代码
    感谢以下博文的参考:1、http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html2、http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-30 02:38 , Processed in 0.442843 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表