zoukankan      html  css  js  c++  java
  • 16种输入输出流介绍

    1.基本概念

    (1)16种流介绍

                                                         

    (2)Input_OutputStream继承结构图

            

    (3)Reader_Writer继承结构图

                                                

    2.基本操作

    2.1.基本读操作- read()方法

    (1)

     1 /*
     2    java.io.InputStream
     3        java.io.FileInputStream
     4        按照字节方式读取
     5 */
     6 import java.io.*;
     7 class  FileInputStreamtest
     8 {
     9     public static void main(String[] args) 
    10     {
    11         FileInputStream fis = null;
    12         try{
    13             //文件路径
    14          //String filePath="text1.txt";//相对路径,在当前路径下
    15         // String filePath="D:\Sourcecode\Editplus\java\file\text1.txt";
    16          String filePath="D:/Sourcecode/Editplus/java/file/text1.txt";
    17          fis = new FileInputStream(filePath);
    18          //读
    19          int i1 = fis.read();//以字节方式读,只能读取一个字母
    20          System.out.println(i1);//输出字母对应的ASSICK值
    21         
    22         }catch(FileNotFoundException e){
    23            e.printStackTrace();
    24         }catch(IOException e){
    25            e.printStackTrace();
    26         }finally{
    27         //保证流一定释放,使用try..catch语句
    28         if(fis!=null){
    29            try{
    30              fis.close();
    31            }catch(IOException e){
    32              e.printStackTrace();
    33            }
    34         }
    35           
    36         }
    37     }
    38 }
    View Code

    (2)

     1 import java.io.*;
     2 class FileInputStreamtest02 
     3 {
     4     public static void main(String[] args) throws Exception  
     5     {
     6         FileInputStream fis = new FileInputStream("text1.txt");
     7         int temp =0;
     8         while((temp=fis.read())!=-1){
     9            System.out.println(temp);
    10         }
    11         fis.close();
    12     }
    13 }
    View Code

    (3)

     1 /*
     2    int read(byte[] bytes)
     3    读取之前在内存中准备一个byte数组,每次读取多个字节存储到byte数组中,一次读取多个字节。
     4    效率高
     5    text1.txt文件中的内容为abcdefg
     6 */
     7 import java.io.*;
     8 class FileInputStreamtest03 
     9 {
    10     public static void main(String[] args) throws Exception
    11     {
    12         FileInputStream fis = new FileInputStream("text1.txt");
    13         byte[] bytes = new byte[3];//每次读3个字节
    14 
    15         int i1 = fis.read(bytes);
    16         System.out.println(new String(bytes));//abc
    17         int i2 = fis.read(bytes);
    18         System.out.println(new String(bytes));//def
    19         int i3 = fis.read(bytes);
    20         System.out.println(new String(bytes));//gef
    21         System.out.println(new String(bytes,0,i3));//g
    22         int i4 = fis.read(bytes);
    23       
    24       //int类型的i表示每次读取的字节数
    25         System.out.println(i1);//3
    26         System.out.println(i2);//3
    27         System.out.println(i3);//1
    28         System.out.println(i4);//-1
    29 
    30     }
    31 }
    View Code

    (4)

     1 /*
     2   循环读取
     3   text1.txt文件中的内容为abcdefg
     4 */
     5 import java.io.*;
     6 class FileInputStreamtest04 
     7 {
     8     public static void main(String[] args) throws Exception 
     9     {
    10         FileInputStream fis = new FileInputStream("text1.txt");
    11         byte[] bytes = new byte[1024];//每次读3个字节
    12          int temp =0;
    13          while((temp=fis.read(bytes))!=-1){
    14            System.out.print(new String(bytes,0,temp));
    15          }
    16          fis.close();
    17     }
    18 }
    View Code

    2.2.available()方法和skip()方法

     1 import java.io.*;
     2 /*
     3   available()方法:返回流中剩余的字节数
     4   skip(n)方法:跳过n个字节不读取
     5    text1.txt文件中的内容为abcdefg
     6 */
     7 class FileInputStreamtest05 
     8 {
     9     public static void main(String[] args) throws Exception
    10     {
    11         FileInputStream fis = new FileInputStream("text1.txt");
    12         System.out.println(fis.available());//7
    13         System.out.println(fis.read());//97
    14         System.out.println(fis.available());//6
    15         fis.skip(2);//跳过两个字节不读取
    16          System.out.println(fis.read());//100
    17         fis.close();
    18         
    19     }
    20 }
    View Code

    2.3.写入数据的方法

     1 /*
     2   java.io.OutputStream
     3     java.io.FileOutputStream;文件字节输出流
     4     将计算机内存中的数据写入硬盘文件中
     5 */
     6 import java.io.*;
     7 class  FileOutputStreamtest01
     8 {
     9     public static void main(String[] args) 
    10     {
    11          FileOutputStream fos=null;
    12         try{
    13            //fos= new FileOutputStream("text2.txt");//多次运行,会覆盖源文件内容
    14            fos= new FileOutputStream("text2.txt",true);//追加写入
    15           //写入
    16           String msg = "Hello World";
    17           //将String转换成byte数组
    18           byte[] bytes = msg.getBytes();
    19           fos.flush();//强制写入,保证数据完全写入硬盘,与、需要刷新
    20           //fos.write(bytes);//强制写入,写入全部
    21           fos.write(bytes,0,3);//写入3个,将byte数组部分写入
    22 
    23         }catch(Exception e){
    24           e.printStackTrace();
    25         }finally{
    26             if(fos!=null){
    27                try{
    28                  fos.close();
    29                }catch(Exception e){
    30                  e.printStackTrace();
    31                }
    32             }
    33            
    34         }
    35     }
    36 }
    View Code

    2.4.文件的复制粘贴

      FileInputStream  FileOutputStream

     1 /*
     2    文件的复制粘贴
     3 */
     4 import java.io.*;
     5 class Copy01 
     6 {
     7     public static void main(String[] args) throws Exception
     8     {
     9         FileInputStream fis = new FileInputStream("text1.txt");
    10         FileOutputStream fos = new FileOutputStream("text2.txt");
    11         //读,写
    12         byte[] bytes = new byte[1024];
    13         int temp = 0;
    14         while((temp=fis.read(bytes))!=-1){
    15           fos.write(bytes,0,temp);
    16         }
    17         fis.close();
    18         fos.close();
    19 
    20     }
    21 }
    View Code

      fileReader,FileWriter

     1 /*
     2  文件复制,只能复制纯文本文件
     3 */
     4 import java.io.*;
     5 class  Copy02
     6 {
     7     public static void main(String[] args) throws Exception
     8     {
     9         FileReader fr = new FileReader("text1.txt");//一个已经存在的文件
    10         FileWriter fw = new FileWriter("text4.txt");//运行后复制出一个文件
    11         char [] chars = new char[1024];
    12         int temp =0;
    13         while((temp=fr.read(chars)) != -1){
    14           fw.write(chars,0,temp);
    15         }
    16         fw.flush();
    17         fr.close();
    18         fw.close();
    19     }
    20 }
    View Code

    2.5.FileWriter()方法写入文件

     1 /*
     2     java.io.Writer;
     3       java.io.OutputStream;转换流
     4         java.io.FileWriter文件字符输出流
     5 */
     6 import java.io.*;
     7 class FileWritertest01 
     8 {
     9     public static void main(String[] args) throws Exception
    10     {
    11         FileWriter fw = new FileWriter("text3.txt",true);
    12          fw.write("写入文件");//直接写入字符串
    13          char [] chars = {'写','入','文','件','{','。','、',};
    14          fw.write(chars,0,6);
    15          fw.flush();
    16         fw.close();
    17     }
    18 }
    19 /*
    20 运行结果:
    21 写入文件写入文件{。
    22 */
    View Code

    2.6.BufferedReader带有缓冲区的字符输入流

     1 /*
     2   readLine() 方法一次读取一行文本
     3 */
     4 import java.io.*;
     5 class  BufferedReadertest01
     6 {
     7     public static void main(String[] args) throws Exception
     8     {
     9         BufferedReader br = new BufferedReader(new FileReader("BufferedReadertest01.java"));
    10         String temp = null;
    11         while((temp=br.readLine())!=null){
    12           System.out.println(temp);
    13         }
    14         br.close();
    15     }
    16 }
    View Code
     1 /*
     2   readLine() 方法一次读取一行文本
     3 */
     4 import java.io.*;
     5 class  BufferedReadertest02
     6 {
     7     public static void main(String[] args) throws Exception
     8     {
     9         FileInputStream fis = new FileInputStream("BufferedReadertest01.java");//文件字节输入流
    10         InputStreamReader brs = new InputStreamReader(fis); //将字节流转换成字符流
    11         BufferedReader br = new BufferedReader(brs);//brs是字符流
    12        //将上面的语句合并
    13      //  BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("BufferedReadertest01.java")));
    14         String temp = null;
    15         while((temp=br.readLine())!=null){
    16           System.out.println(temp);
    17         }
    18         br.close();
    19     }
    20 }
    View Code

    3.文件输入/输出流

    1.FileinputStream 与FileOutputStream类将文件读出与写入。

    2.FileReader和FileWriter将文件读出与写入。

      二者的区别:

      使用FileOutputStream类向文件中写入数据与使用FileinputStream类从文件中将内容读出来都存在一点不足,即这两个类都只有提供了对字节或字节数组的读取方法,由于汉子在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码的情况,此时采用字符流Reader或Writer类即可避免这种现象。

      FileReader和FileWriter字符流对应了FileinputStream 与FileOutputStream类,FileReader流顺序地读取文件,只要不关闭流,每次调用read()方法就顺序地读取源文件中其余内容,直到源的末尾或流被关闭。

     1 import java.io.File;
     2 import java.io.FileInputStream;
     3 import java.io.FileOutputStream;
     4 
     5 public class FileTest3 {
     6      
     7     public static void main(String[] args) {
     8        File file = new File("D:/Sourcecode/Java/file/word1.txt");
     9        try{
    10            FileOutputStream out = new FileOutputStream(file);
    11            byte buy[]  ="风住尘香花已尽,日晚倦梳头。物是人非事事休,欲语泪先流。".getBytes();
    12            out.write(buy);
    13            out.close();
    14        }catch(Exception e){
    15            e.printStackTrace();
    16        }
    17        try{
    18            FileInputStream inputStream = new FileInputStream(file);
    19            byte byt[] = new byte[1024];
    20            int len  =inputStream.read(byt);
    21            System.out.print("文件中的信息是: "+ new String(byt,0,len));
    22            inputStream.close();
    23        }catch(Exception e){
    24            e.printStackTrace();
    25        }
    26     }
    27 
    28 }
    View Code
      1 import java.awt.*;
      2 import java.awt.event.*;
      3 import java.io.*;
      4 
      5 import javax.swing.*;
      6 
      7 public class Ftest extends JFrame { // 创建类,继承Jframe类
      8     private JScrollPane scrollPane;
      9     private static final long serialVersionUID = 1L;
     10     private JPanel jContentPane = null; // 创建面板对象
     11     private JTextArea jTextArea = null; // 创建文本域对象
     12     private JPanel controlPanel = null; // 创建面板对象
     13     private JButton openButton = null; // 创建按钮对象
     14     private JButton closeButton = null; // 创建按钮对象
     15     
     16     private JTextArea getJTextArea() {
     17         if (jTextArea == null) {
     18             jTextArea = new JTextArea();
     19         }
     20         return jTextArea;
     21     }
     22     
     23     private JPanel getControlPanel() {
     24         if (controlPanel == null) {
     25             FlowLayout flowLayout = new FlowLayout();
     26             flowLayout.setVgap(1);
     27             controlPanel = new JPanel();
     28             controlPanel.setLayout(flowLayout);
     29             controlPanel.add(getOpenButton(), null);
     30             controlPanel.add(getCloseButton(), null);
     31         }
     32         return controlPanel;
     33     }
     34     
     35     private JButton getOpenButton() {
     36         if (openButton == null) {
     37             openButton = new JButton();
     38             openButton.setText("写入文件"); // 修改按钮的提示信息
     39             openButton
     40                     .addActionListener(new java.awt.event.ActionListener() {
     41                         // 按钮的单击事件
     42                         public void actionPerformed(ActionEvent e) {
     43                             // 创建文件对象
     44                             File file = new File("word.txt");
     45                             try {
     46                                 // 创建FileWriter对象
     47                                 FileWriter out = new FileWriter(file);
     48                                 // 获取文本域中文本
     49                                 String s = jTextArea.getText();
     50                                 out.write(s); // 将信息写入磁盘文件
     51                                 out.close(); // 将流关闭
     52                             } catch (Exception e1) {
     53                                 e1.printStackTrace();
     54                             }
     55                         }
     56                     });
     57         }
     58         return openButton;
     59     }
     60     
     61     private JButton getCloseButton() {
     62         if (closeButton == null) {
     63             closeButton = new JButton();
     64             closeButton.setText("读取文件"); // 修改按钮的提示信息
     65             closeButton
     66                     .addActionListener(new java.awt.event.ActionListener() {
     67                         // 按钮的单击事件
     68                         public void actionPerformed(ActionEvent e) {
     69                             File file = new File("word.txt"); // 创建文件对象
     70                             try {
     71                                 // 创建FileReader对象
     72                                 FileReader in = new FileReader(file);
     73                                 char byt[] = new char[1024]; // 创建char型数组
     74                                 int len = in.read(byt); // 将字节读入数组
     75                                 // 设置文本域的显示信息
     76                                 jTextArea.setText(new String(byt, 0, len));
     77                                 in.close(); // 关闭流
     78                             } catch (Exception e1) {
     79                                 e1.printStackTrace();
     80                             }
     81                         }
     82                     });
     83         }
     84         return closeButton;
     85     }
     86     
     87     public Ftest() {
     88         super();
     89         initialize();
     90     }
     91     
     92     private void initialize() {
     93         this.setSize(300, 200);
     94         this.setContentPane(getJContentPane());
     95         this.setTitle("JFrame");
     96     }
     97     
     98     private JPanel getJContentPane() {
     99         if (jContentPane == null) {
    100             jContentPane = new JPanel();
    101             jContentPane.setLayout(new BorderLayout());
    102             jContentPane.add(getScrollPane(), BorderLayout.CENTER);
    103             jContentPane.add(getControlPanel(), BorderLayout.SOUTH);
    104         }
    105         return jContentPane;
    106     }
    107     
    108     public static void main(String[] args) { // 主方法
    109         Ftest thisClass = new Ftest(); // 创建本类对象
    110         thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    111         thisClass.setVisible(true); // 设置该窗体为显示状态
    112     }
    113     /**
    114      * @return
    115      */
    116     protected JScrollPane getScrollPane() {
    117         if (scrollPane == null) {
    118             scrollPane = new JScrollPane();
    119             scrollPane.setViewportView(getJTextArea());
    120         }
    121         return scrollPane;
    122     }
    123 }
    View Code

    4.带缓存的输入输出流

      由于Java中的字符是Unicode编码,是双字节的,writeBytes只是将字符串中的每一个字符的低字节内容写入目标设备中,而writeChars将字符串的每一个字符的两个字节的内容都写到目标设备中,WriterUTF将字符串按照UTF编码后的字节长度写入目标设备,然后才是每一字节的UTF编码。

      DataInputStream类只提供了一个readUTF()方法返回字符串,这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束,DataOutputStream类中只有writeUTF()方法向目标设备中写入字符串的长度,所以也能准确的读回写入的字符串。

    例:

     1 public class Dataintandout {
     2 
     3     public static void main(String[] args) {
     4         try{
     5             //创建FileOutputStream对象
     6             FileOutputStream fStream = new FileOutputStream("D:/Sourcecode/Java/file/word4.txt");
     7             //创建DataOutputStream对象
     8             DataOutputStream dStream = new DataOutputStream(fStream);
     9             dStream.writeUTF("使用writeUTF()方法写入数据:不是无心惜落花,落花无意恋春花");
    10             dStream.writeChars("使用writeChars()方法写入数据:今朝春去谁家落,把酒临风千种恨");
    11             dStream.writeBytes("使用writeBytes()方法写入数据:昨日寒鸦一片愁,柳塘新绿却温柔");
    12             dStream.close();
    13             //创建FileInputStream对象
    14         FileInputStream fileInputStream = new FileInputStream("D:/Sourcecode/Java/file/word4.txt");
    15         //创建DataInputStream对象
    16         DataInputStream dataInputStream = new DataInputStream(fileInputStream);
    17         System.out.println(dataInputStream.readUTF());//将文件输出
    18         }catch(Exception e){
    19             e.printStackTrace();
    20         }
    21     }
    22 
    23 }
    View Code

      运行结果:使用writeUTF()方法写入数据:不是无心惜落花,落花无意恋春花

      打开文本内容如下:

           

      尽管在记事本中出现乱码的情况,但在控制台屏幕上仍然能正确显示内容。但如果使用writeChars()方法和writeBytes()方法写入字符串,就不能正确读出。

      带缓存的输入输出流

      缓存是I/o的一种性能优化,带缓存为I/o流增加了内存缓存区,有了缓存区,使得在流上执行skip(),mark(),reset()方法成为可能。

    4.1.BufferedinputStream与BufferedOutputStream类

    1. BufferedinputStream有两种构造方法:

      (1)BufferedinputStream(inputStream in)

      (2)BufferedinputStream(inputStream in,int size)

      第一种形式的构造方法创建了一个带有32个字节的缓存流,第二种形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统,可用的内存空间以及机器配置。从构造方法可以看出,BufferedinputStream对象位于InputStream类对象之前

     2.BufferedOutputStream类有两种构造方法

      (1)BufferedOutputStream(OutputStream in)

      (2)BufferedOutputStream(OutputStream in,int size)

      第一种构造方法创建了一个有32个字节的缓存区域,第二种构造方法以指定的大小来创建缓存区

      注意:flush()方法是用于即使在缓存区域没有存满的情况下,也将缓存区的内容强制写入到外设,习惯上称这个过程为刷新,flush()方法只对使用缓存区的OutputStream类的子类有效,当调用close()方法时,系统在关闭之前,也将缓存区中的信息刷新到磁盘文件中。

    4.2.BufferedReader与BufferedWriter类

      BufferedReader类常用的方法如下。

      (1)read()方法:读取单个字符。

      (2)readLine()方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回null。BufferedWriter类中的方法都返回void,常用的方法如下:

        a、 write(String s,int off, int len)方法:写入字符串的某一部分。

        b、flush()方法:刷新该流得缓存。

        c、newline()方法:写入一个行分隔符。

       例:

     1 package file;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.File;
     6 import java.io.FileReader;
     7 import java.io.FileWriter;
     8 
     9 public class Student {
    10    public static void main(String []args){
    11        String contet[] = {"夜夜思君情断肠,缘何人不双,夜夜痴迷空自伤,月随人彷徨"};
    12        //创建文件对象
    13        File file = new File("D:/Sourcecode/Java/file/word2.txt");
    14        try{
    15            //创建FileWriter类对象
    16            FileWriter fw = new FileWriter(file);
    17            //创建bufferWriter类对象
    18            BufferedWriter buffw  = new BufferedWriter(fw);
    19            for(int k = 0;k < contet.length;k++){
    20                buffw.write(contet[k]);//将字符串数组中的元素写入到磁盘文件中
    21                buffw.newLine();//将数组中的单个元素以单行的形式写入文件
    22            }
    23            buffw.close();    //将BufferReader流关闭
    24            fw.close();       //将FileWriter流关闭
    25        }catch(Exception e){
    26            e.printStackTrace();
    27        }
    28        try{
    29            //创建FileReader类对象
    30            FileReader fr = new FileReader(file);
    31            //创建BufferReader类对象
    32            BufferedReader bufr = new BufferedReader(fr);
    33            String s = null;//创建字符串对象
    34            int i = 0;    
    35            //如果文件文本行数不为空,则进入循环
    36            while((s = bufr.readLine()) != null){
    37                i++;
    38                System.out.println("第"+i+"行"+s);
    39            }
    40            bufr.close();
    41            fr.close();
    42            
    43        }catch(Exception e){
    44            e.printStackTrace();
    45        }
    46    }
    47 }
    View Code

      运行结果:

      第1行夜夜思君情断肠,缘何人不双,
      第2行夜夜痴迷空自伤,月随人彷徨

    5.序列化和反序列化-对象流

    5.1.序列化-ObjectOutputStream

      序列化就是将堆中的Java对象存入到硬盘中。

     1 import java.io.Serializable;//可序列化的,没有任何方法的标识接口
     2 class  User implements Serializable
     3 {
     4     String name;
     5     User(String name){
     6       this.name = name;
     7     }
     8     public String toString(){
     9       return "User[name="+name+"]";
    10     }
    11 }
    View Code

      注:  User 实现了 Serializable  接口 JVM会给该类添加自动一个属性:序列化版本号。(可以自定义一个序列化版本号,则系统不会再成序列化版本号,

    也不会出现版本号不相同的情况)

      例:自定义序列化版本号

    static final long seriaVersionUID="xxxxxxxxx";

      如果不让某个属性参与序列化,可以使用transient关键字修饰;

    transient String name;
     1 /*
     2    java.io.ObjectOutputStream;序列化Java对象到硬盘
     3    java.io.ObjectInputStream;将硬盘中的数据反序列化到jvm内存
     4 */
     5 import java.io.*;
     6 class  ObjectOutputStreamtest01
     7 {
     8     public static void main(String[] args) throws Exception 
     9     {
    10         //创建Java对象
    11         User u1 = new User("Java对象");
    12         //创建输出流(序列化流)jvm中的java对象状态保存到硬盘中
    13         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("text6.txt"));
    14         //
    15         oos.writeObject(u1);
    16         oos.flush();
    17         oos.close();
    18     }
    19 }
    View Code

    5.2.反序列化-ObjectInputStream

      反序列化就是将硬盘中的对象恢复到内存中。

     1 /*
     2    反序列化
     3 */
     4 import java.io.*;
     5 class  ObjectInputStreamtest01
     6 {
     7     public static void main(String[] args) throws Exception
     8     {
     9         //创建反序列化流
    10         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("text6.txt"));
    11         //反序列化
    12         Object o = ois.readObject();
    13         System.out.println(o);
    14         ois.close();
    15     }
    16 }
    17 /*
    18 User[name=Java对象]
    19 请按任意键继续. . .
    20 */
    View Code

    6.File

    6.1.特点

      Java.io.File;File类和流无关,不能通过该类完成文件的读和写,File是文件和目录路径名的抽象表示形式,File代表的是硬盘上的文件夹和文件名。

    6.2.常用方法

     1 import java.io.*;
     2 /*
     3    判断指定路径或文件是否存在,不存在则创建
     4 */
     5 class Filetest01 
     6 {
     7     public static void main(String[] args) throws Exception 
     8     {
     9         //相对路径
    10         File f1 = new File("text1.txt");
    11         //绝对路径
    12         File f2 = new File("D:\Sourcecode\Editplus\java");
    13         
    14         System.out.println(f1.exists());//true
    15         System.out.println(f2.exists());//true
    16 
    17         File f3 = new File("D:\Sourcecode\Editplus\java\AA");
    18         System.out.println(f3.exists());//false
    19        //如果不存在则创建
    20        if(!f3.exists()){
    21          //创建目录
    22          //f3.mkdir();
    23          //创建文件
    24          f3.createNewFile();
    25        }
    26        File f4 = new File("D:/a/b/c");
    27        if(!f4.exists()){
    28          //创建多重目录
    29          f4.mkdirs();
    30        }
    31     }
    32 }
    View Code
  • 相关阅读:
    database backup scripts
    RMAN笔记之备份集和备份片
    数据缓冲区详解
    Oracle数据库中快照的使用
    linux 安装RabbitMQ 注意版本
    转 Oracle12c/11个 Client安装出现"[INS-30131]"错误“请确保当前用户具有访问临时位置所需的权限”解决办法之完整版
    Oracle alert日志中出现:‘Fatal NI connect error 12170’
    Oracle表分区分为四种:范围分区,散列分区,列表分区和复合分区
    python基础: String类型
    Python3 urllib模块的使用(转载)
  • 原文地址:https://www.cnblogs.com/xyzyj/p/6184709.html
Copyright © 2011-2022 走看看