java中的IO整理

【案例1】创建一个新文件

 1 import java.io.*; 
 2 class hello{ 
 3     public static void main(String[] args) { 
 4         File f=new File("D:\\hello.txt"); 
 5         try{ 
 6             f.createNewFile(); 
 7         }catch (Exception e) { 
 8             e.printStackTrace(); 
 9         } 
10     } 
11 }

【运行结果】:

程序运行之后,在d盘下会有一个名字为hello.txt的文件。

【案例2】File类的两个常量

1 import java.io.*; 
2 class hello{ 
3     public static void main(String[] args) { 
4         System.out.println(File.separator); 
5         System.out.println(File.pathSeparator); 
6     } 
7 }

【运行结果】:

\

;

此处多说几句:有些同学可能认为,我直接在windows下使用\进行分割不行吗?当然是可以的。但是在linux下就不是\了。windows是\,unix是/。所以,要想使得我们的代码跨平台,更加健壮,所以,大家都采用这两个常量吧,其实也多写不了几行。

 

现在我们使用File类中的常量改写【案例1】的代码:

 1 import java.io.File;
 2 
 3 public class hello3 {
 4 
 5     public static void main(String[] args) {
 6         String path="D:"+File.separator+"hello.txt";
 7         File f=new File(path);
 8         try{ 
 9             f.createNewFile(); //创建文件
10         }catch (Exception e) { 
11             e.printStackTrace(); 
12         }
13     }
14 }

【运行结果】:

D盘下多了一个hello文件

 1 import java.io.File;
 2 /**
 3  * 删除文件
 4  */
 5 public class hello4 {
 6     public static void main(String[] args) {
 7         String path="D:"+File.separator+"hello.txt";
 8         File f=new File(path);
 9         if(f.exists()){
10             f.delete();
11         }else{
12             System.out.println("文件不存在"); 
13         }
14     }
15 }

【运行结果】:

删除D盘下一个hello文件

 1 import java.io.File;
 2 /**
 3  * 创建一个文件夹
 4  */
 5 public class hello5 {
 6     public static void main(String[] args) {
 7         File f=new File("D:"+File.separator+"hello");
 8         f.mkdir();
 9     }
10 }
 1 import java.io.File;
 2 /**
 3  * 删除一个文件夹
 4  */
 5 public class hello6 {
 6     public static void main(String[] args) {
 7         File f=new File("D:"+File.separator+"hello");
 8         if(f.exists()){
 9             f.delete();
10         }else{
11             System.out.println("文件夹不存在"); 
12         }
13     }
14 }

列出指定目录的全部文件(包括隐藏文件):

 1 import java.io.File;
 2 /**
 3  * 使用list列出指定目录的全部文件
 4  */
 5 public class hello7 {
 6     public static void main(String[] args) {
 7         File f=new File("D:"+File.separator);
 8         String[] str=f.list();
 9         for(int i=0;i<str.length;i++){
10             System.out.println(str[i]);
11         }
12     }
13 }

【运行结果】:

(你的运行结果应该和这个不一样的,呵呵)

但是使用list返回的是String数组,。而且列出的不是完整路径,如果想列出完整路径的话,需要使用listFiles.他返回的是File的数组

import java.io.File;
/**
 * 使用listFiles列出指定目录的全部文件
 * listFiles输出的是完整路径
 */
public class hello8 {
    public static void main(String[] args) {
        File f=new File("D:"+File.separator);
        File[] str=f.listFiles();
        for(int i=0;i<str.length;i++){
            System.out.println(str[i]);
        }
    }
}

【运行结果】:

D:\AndroidWorkSpace
D:\apache-maven-3.0.3
D:\document
D:\eclipse
D:\Eclipse 3.5.1
D:\ECLIPSE配置.txt
D:\GouWoGames
D:\Installation
D:\jdk1.6.0_07
D:\jdk1.6.0_14

 通过比较可以指定,使用listFiles更加方便

判断一个指定的路径是否为目录

 1 import java.io.File;
 2 /**
 3  * 使用isDirectory判断一个指定的路径是否为目录
 4  */
 5 public class hello9 {
 6     public static void main(String[] args) {
 7         File f=new File("D:"+File.separator);
 8         if(f.isDirectory()){
 9             System.out.println("YES");
10         }else{
11             System.out.println("NO");
12         }
13     }
14 }

【运行结果】:YES

搜索指定目录的全部内容

 1 import java.io.File;
 2 /**
 3  * 列出指定目录的全部内容
 4  */
 5 public class hello10 {
 6     public static void main(String[] args) {
 7         File f = new File("D:" + File.separator);
 8         print(f);
 9     }
10     public static void print(File f){
11         if(f!=null){
12         if(f.isDirectory()){
13             File[] fileList=f.listFiles();
14             if(fileList!=null){
15                 for(int i=0;i<fileList.length;i++){
16                     System.out.print(fileList[i]);//递归调用
17                 }
18             }
19         }else{
20             System.out.println(f);
21         }
22         }
23     }
24 }

【运行结果】:

D:\springsource\sts-3.1.0.RELEASE\features\org.eclipse.wst.xml_ui.feature_3.4.1.v201208170345-7H7GFeFDxumUpsw5rgjWnKDrsz0p4ymwjQz00T2S\META-INF\MANIFEST.MF
D:\springsource\sts-3.1.0.RELEASE\features\org.eclipse.wst.xml_ui.feature_3.4.2.v201211061806-7H7GFeJDxumUrsn5qkiQgOEhsz0p60HAmPyU6VX\eclipse_update_120.jpg
D:\springsource\sts-3.1.0.RELEASE\features\org.eclipse.wst.xml_ui.feature_3.4.2.v201211061806-7H7GFeJDxumUrsn5qkiQgOEhsz0p60HAmPyU6VX\epl-v10.html
D:\springsource\sts-3.1.0.RELEASE\features\org.eclipse.wst.xml_ui.feature_3.4.2.v201211061806-7H7GFeJDxumUrsn5qkiQgOEhsz0p60HAmPyU6VX\feature.properties 

 

使用RandomAccessFile写入文件

 1 import java.io.*;
 2 /**
 3  * 使用RandomAccessFile写入文件
 4  */
 5 public class hell012 {
 6     public static void main(String[] args) throws IOException {
 7         String fileName="D:"+File.separator+"hello.txt";
 8         File f=new File(fileName);
 9         RandomAccessFile demo=new RandomAccessFile(f, "rw");
10         demo.writeBytes("asdsad");
11         demo.writeInt(12);
12         demo.writeBoolean(true);
13         demo.writeChar('A');
14         demo.writeFloat(1.21f);
15         demo.writeDouble(12.123);
16         demo.close();        
17     }
18 }

【运行结果】:

D盘下创建hello.txt文件,打开查看的话,会发现那是乱码。

字节流

 1 import java.io.*;
 2 /**
 3  * 字节流
 4  * 向文件中写入字符串
 5  */
 6 public class hell012 {
 7     public static void main(String[] args) throws IOException {
 8         String fileName = "D:" + File.separator + "hello.txt";
 9         File f = new File(fileName);
10         OutputStream out = new FileOutputStream(f);
11         String str = "你好!";
12         byte[] b = str.getBytes();
13         out.write(b);
14         out.close();
15     }
16 }

【运行结果】:

查看hello.txt会看到“你好”

当然也可以一个字节一个字节的写。

import java.io.*;
/**
 * 字节流
 * 向文件中写入字符串
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        OutputStream out = new FileOutputStream(f);
        String str = "羞答答的玫瑰静悄悄的开!";
        byte[] b = str.getBytes();
        for(int i=0;i<b.length;i++){
            out.write(b[i]);
        }
        out.close();
    }
}

【运行结果】:

查看hello.txt会看到“羞答答的玫瑰静悄悄的开!”

向文件中追加新内容:

 1 import java.io.*;
 2 /**
 3  * 字节流
 4  * 向文件中追加新内容:
 5  */
 6 public class hell012 {
 7     public static void main(String[] args) throws IOException {
 8         String fileName = "D:" + File.separator + "hello.txt";
 9         File f = new File(fileName);
10         OutputStream out = new FileOutputStream(f,true);
11         String str = "春天到了";
12         byte[] b = str.getBytes();
13         for(int i=0;i<b.length;i++){
14             out.write(b[i]);
15         }
16         out.close();
17     }
18 }

 【运行结果】:

查看hello.txt会看到:羞答答的玫瑰静悄悄的开!春天到了

【读取文件内容】

import java.io.*;
/**
 * 字节流
 *  读取文件内容
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        in.read(b);
        in.close();
        System.out.println(new String(b));
    }
}

【运行结果】:

控制台看到:羞答答的玫瑰静悄悄的开!春天到了_____

但是这个例子读取出来会有大量的空格,我们可以利用in.read(b);的返回值来设计程序。如下:

 

import java.io.*;
/**
 * 字节流
 *  读取文件内容,无空白
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        int len=in.read(b);
        in.close();
        System.out.println("读入长度为:"+len);
        System.out.println(new String(b, 0, len));
    }
}

【运行结果】:

读入长度为:32
羞答答的玫瑰静悄悄的开!春天到了

观察上面的例子可以看出,我们预先申请了一个指定大小的空间,为1024(byte[] b=new byte[1024];)但是有时候这个空间可能太小,有时候可能太大,我们需要准确的大小,这样节省空间,那么我们可以这样干:

 

import java.io.*;
/**
 * 字节流
 *  读取文件内容,无空白,且节省空间
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[(int)f.length()];
        in.read(b);
        in.close();
        System.out.println("读入长度为:"+f.length());
        System.out.println(new String(b));
    }
}

【运行结果】:

读入长度为:32 羞答答的玫瑰静悄悄的开!春天到了

在调试的时候可以观察到byte[] b的长度为32。

将上面的例子改为一个一个读:

import java.io.*;
/**
 * 字节流
 *  读取文件内容,无空白,一个一个字节读
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[(int)f.length()];
        for(int i=0;i<b.length;i++){
            b[i]=(byte)in.read();
        }
        in.close();
        System.out.println("读入长度为:"+f.length());
        System.out.println(new String(b));
    }
}

【运行结果】:

读入长度为:32

羞答答的玫瑰静悄悄的开!春天到了

有时候我们不知道文件有多大,这种情况下,我们可以通过判断是否独到文件的末尾来读取文件哦:

 

import java.io.*;
/**
 * 字节流
 *  通过判断是否到达文件末尾来读取文件内容
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        int count=0,tmp=0;
        while((tmp=in.read())!=(-1)){
            b[count++]=(byte)tmp;
        }
        in.close();        
        System.out.println(new String(b));
    }
}

【运行结果】:

羞答答的玫瑰静悄悄的开!春天到了

提醒一下,当独到文件末尾的时候会返回-1.正常情况下是不会返回-1

字符流

【向文件中写入数据】

现在我们使用字符流

import java.io.*;
/**
 * 字符流
 *  写入数据
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        Writer out=new FileWriter(f);
        String str="hello";
        out.write(str);
        out.close();
    }
}

【运行结果】:

当你打开hellotxt的时候,会看到hello

当你打开hello。txt的时候,会看到hello

其实这个例子上之前的例子没什么区别,只是你可以直接输入字符串,而不需要你将字符串转化为字节数组。

当你如果想问文件中追加内容的时候,可以使用将上面的声明out的哪一行换为:

Writer out =new FileWriter(f,true);

这样,当你运行程序的时候,会发现文件内容变为:

hellohello如果想在文件中换行的话,需要使用“\r\n”

比如将str变为String str="\r\nhello";

这样文件追加的str的内容就会换行了。

从文件中读内容

import java.io.*;
/**
 * 字符流
 * 从文件中读出内容
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        char[] ch=new char[100];
        Reader read=new FileReader(f);
        int count=read.read(ch);
        read.close();
        System.out.println("读入的长度为:"+count);
        System.out.println("内容为:"+new String(ch,0,count));
    }
}

【运行结果】:

读入的长度为:13

内容为:hello

hello

当然最好采用循环读取的方式,因为我们有时候不知道文件到底有多大。

 

import java.io.*;
/**
 * 字符流
 * 从文件中读出内容
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        char[] ch=new char[100];
        Reader read=new FileReader(f);
        int tmp=0,count=0;
        while((tmp=read.read())!=(-1)){
            ch[count++]=(char)tmp;
        }
        read.close();
        System.out.println("读入的长度为:"+count);
        System.out.println("内容为:"+new String(ch,0,count));
    }
}

【运行结果】:

读入的长度为:13

内容为:hello

hello

我们也可以这样来处理:

import java.io.*;
/**
 * 字符流
 * 从文件中读出内容
 */
public class hell012 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:" + File.separator + "hello.txt";
        File f = new File(fileName);
        Reader read=new FileReader(f);
        int count=(int) f.length();
        char[] ch=new char[count];
        read.read(ch);
        read.close();
        System.out.println("读入的长度为:"+f.length());
        System.out.println("内容为:"+new String(ch,0,count));
    }
}


运行结果一样。

关于字节流和字符流的区别

实际上字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的,但是字符流在操作的 时候下后是会用到缓冲区的,是通过缓冲区来操作文件的。

读者可以试着将上面的字节流和字符流的程序的最后一行关闭文件的代码注释掉,然后运行程序看看。你就会发现使用字节流的话,文件中已经存在内容,但是使用字符流的时候,文件中还是没有内容的,这个时候就要刷新缓冲区。

使用字节流好还是字符流好呢?

答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。

文件的复制

其实DOS下就有一个文件复制功能,比如我们想把d盘下面的hello.txt文件复制到d盘下面的a.txt文件中,那么我们就可以使用下面的命令:

copy d:\hello.txt d:\a.txt

运行之后你会在d盘中看见hello.txt.,并且两个文件的内容是一样的,(这是屁话)
 

下面我们使用程序来复制文件吧。

基本思路还是从一个文件中读入内容,边读边写入另一个文件,就是这么简单。、

首先编写下面的代码:

import java.io.*;
/**
 * 文件的复制
 * */
class hello{
    public static void main(String[] args) throws IOException {
        if(args.length!=2){
            System.out.println("命令行参数输入有误,请检查");
            System.exit(1);
        }
        File file1=new File(args[0]);
        File file2=new File(args[1]);      
        if(!file1.exists()){
            System.out.println("被复制的文件不存在");
            System.exit(1);
        }
        InputStream input=new FileInputStream(file1);
        OutputStream output=new FileOutputStream(file2);
        if((input!=null)&&(output!=null)){
            int temp=0;
            while((temp=input.read())!=(-1)){
                output.write(temp);
            }
        }
        input.close();
        output.close(); 
    }
}

然后在命令行下输入命令:

javac hello.java 

java hello d:\hello.txt d:\rollen.txt

现在你就会在d盘看到a.txt了

OutputStreramWriter 和InputStreamReader类

整个IO类中除了字节流和字符流还包括字节和字符转换流。

OutputStreramWriter将输出的字符流转化为字节流

InputStreamReader将输入的字节流转换为字符流

但是不管如何操作,最后都是以字节的形式保存在文件中。

将字节输出流转化为字符输出流

import java.io.*;
/**
 * 将字节输出流转化为字符输出流
 * */
class hello{
    public static void main(String[] args) throws IOException {
        String fileName="D:"+File.separator+"hello.txt";
        File file=new File(fileName);
        Writer out=new OutputStreamWriter(new FileOutputStream(file));
        out.write("hello");
        out.close();
    }
}

【运行结果】:

hello.txt文件中内容为:hello

 将字节输入流变为字符输入流

import java.io.*;
/**
 * 将字节输入流变为字符输入流
 * */
class hello{
    public static void main(String[] args) throws IOException {
        String fileName="D:"+File.separator+"hello.txt";
        File file=new File(fileName);
        Reader read=new InputStreamReader(new FileInputStream(file));
        int len=(int) file.length();
        char[] b=new char[len];
        read.read(b);
        System.out.println(new String(b,0,b.length));
        read.close();
    }
}

【运行结果】:

hello

前面列举的输出输入都是以文件进行的,现在我们以内容为输出输入目的地,使用内存操作流

ByteArrayInputStream 主要将内容写入内容

ByteArrayOutputStream  主要将内容从内存输出

使用内存操作流将一个大写字母转化为小写字母

import java.io.*;
/**
 * 使用内存操作流将一个大写字母转化为小写字母
 * */
class hello{
    public static void main(String[] args) throws IOException {
        String str="ASDSDSDSDFG";
        ByteArrayInputStream input=new ByteArrayInputStream(str.getBytes());
        ByteArrayOutputStream output=new ByteArrayOutputStream();
        int tmp=0;
        while((tmp=input.read())!=(-1)){
            char ch=(char)tmp;
            output.write(Character.toLowerCase(ch));
        }
        String outStr=output.toString();
        input.close();
        output.close();
        System.out.println(outStr);
    }
}

【运行结果】:

asdsdsdsdfg

内容操作流一般使用来生成一些临时信息采用的,这样可以避免删除的麻烦。

管道流 

管道流主要可以进行两个线程之间的通信。

PipedOutputStream 管道输出流 

PipedInputStream 管道输入流

验证管道流

 

/**
* 验证管道流
 * */
import java.io.*;
 /**
 * 消息发送类
 * */
class Send implements Runnable{
    private PipedOutputStream out=null;
    public Send() {
    out=new PipedOutputStream();
    }
    public PipedOutputStream getOut(){
       return this.out;
    }
    public void run(){
        String message="hello , echo";
        try{
            out.write(message.getBytes());
       }catch (Exception e) {
            e.printStackTrace();
        }try{
           out.close();
        }catch (Exception e) {
           e.printStackTrace();
        }
    }
}
/**
 * 接受消息类
 * */
class Receive implements Runnable{
    private PipedInputStream input=null;
    public Receive(){
        this.input=new PipedInputStream();
    }
    public PipedInputStream getInput(){
        return this.input;
    }
    public void run(){
        byte[] b=new byte[1000];
        int len=0;
        try{
            len=this.input.read(b);
        }catch (Exception e) {
            e.printStackTrace();
        }try{
            input.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("接受的内容为 "+(new String(b,0,len)));
    }
}
/**
 * 测试类
 * */
class hello{
    public static void main(String[] args) throws IOException {
        Send send=new Send();
        Receive receive=new Receive();
        try{
            //管道连接
            send.getOut().connect(receive.getInput());
        }catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(send).start();
        new Thread(receive).start();
    }
}

【运行结果】:

打印的内容为 hello , echo

打印流

/**
 * 使用PrintStream进行输出
 * */
import java.io.*;
class hello {
    public static void main(String[] args) throws IOException {
        PrintStream print = new PrintStream(new FileOutputStream(new File("d:"
                + File.separator + "hello.txt")));
        print.println(true);
        print.println("echo");
        print.close();
    }
}

【运行结果】:

hello.txt打印:

true

echo

当然也可以格式化输出

/**
 * 使用PrintStream进行输出
 * 并进行格式化
 * */
import java.io.*;
class hello {
    public static void main(String[] args) throws IOException {
        PrintStream print = new PrintStream(new FileOutputStream(new File("d:"
                + File.separator + "hello.txt")));
        String name="echo";
        int age=20;
        print.printf("姓名:%s  年龄:%d ",name,age);
        print.close();
    }
}

【运行结果】:

hello.txt打印:

姓名:echo  年龄:20

使用OutputStream向屏幕上输出内容

/**
 * 使用OutputStream向屏幕上输出内容
 */
import java.io.*;
class hello {
    public static void main(String[] args) throws FileNotFoundException {
        OutputStream  out=System.out;
        try{
            out.write("hello".getBytes());
        }catch(Exception e){
            e.printStackTrace();
        }try{
            out.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

【运行结果】:

hello

输入输出重定向

/**
 * 为System.out.println()重定向
 */
import java.io.*;
class hello {
    public static void main(String[] args) throws FileNotFoundException {
        //此刻直接输出到控制台
        System.out.println("hello");
        File file=new File("d:"+File.separator+"hello.txt");
        try{
            System.setOut(new PrintStream(new FileOutputStream(file)));
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("这些内容在文件hello.txt中才能看见哦!");
    }
}

【运行结果】:

控制台输出:hello

hello.txt中:这些内容在文件hello.txt中才能看见哦!

错误信息的重定向,这个例子也提示我们可以使用这种方法保存错误信息

/**
 * System.err重定向
 */
import java.io.*;
class hello {
    public static void main(String[] args) throws FileNotFoundException {
        File file=new File("d:"+File.separator+"hello.txt");
        System.err.println("错误在控制台输出");
        try{
            System.setErr(new PrintStream(new FileOutputStream(file)));
        }catch(Exception e){
            e.printStackTrace();
        }
        System.err.println("错误内容在文件hello.txt中才能看见哦!");
    }
}

【运行结果】:

你会在eclipse的控制台看到红色的输出:“错误在控制台输出”,然后在d盘下面的hello.txt中会看到:错误内容在文件hello.txt中才能看见哦!

输入重定向

/**
 * System.in重定向
 */
import java.io.*;
class hello {
    public static void main(String[] args){
        File file=new File("d:"+File.separator+"hello.txt");
        if(!file.exists()){
            return;
        }else{
            try{
                System.setIn(new FileInputStream(file));
            }catch(Exception e){
                e.printStackTrace();
            }
            byte[] b=new byte[1024];
            int len=0;
            try{
                len=System.in.read(b);
            }catch(Exception e){
                e.printStackTrace();
            }
            System.out.println("读入的内容为:"+new String(b,0,len));
        }
    }
}

【运行结果】:

前提是我的d盘下面的hello.txt中的内容是:“这些是hello.txt文件中的内容哦!”,然后运行程序,输出的结果为:

读入的内容为:这些是hello.txt文件中的内容哦!

 

BufferedReader的小例子

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

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

/**
 * 使用缓冲区从键盘上读入内容
 */
import java.io.*;
class hello {
    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(Exception e){
            e.printStackTrace();
        }
        System.out.println("你输入的内容是:"+str);
    }
}

 【运行结果】:

请输入内容:
你好啊
你输入的内容是:你好啊

Scanner

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

/**
 * 使用Scanner从键盘读数据
 */
import java.util.Scanner;
class hello {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        //读一个整数
        int tmp=in.nextInt();
        System.out.println(tmp);
        //读一个浮点数
        float f=in.nextFloat();
        System.out.println(f);
        //读一个字符串
        String str=in.next();
        System.out.println(str);
        //...等等的,都是一些太基础的,就不师范了。
} }

【运行结果】:

22
22
2.01
2.01
ssssssssss
ssssssssss

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

/**
 * 使用Scanner从文件中读取内容
 */
import java.io.File;
import java.util.Scanner;
class hello {
    public static void main(String[] args) {
        File file=new File("d:"+File.separator+"hello.txt");
        Scanner in=null;
        try{
            in=new Scanner(file);
        }catch(Exception e){
            e.printStackTrace();
        }
        String str=in.next();
        System.out.println("从文件读取的内容是这些:"+str);
    }
}

【运行结果】:

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

数据操作流DataOutputStreamDataInputStream
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 数据操作流DataOutputStream、DataInputStream类
 */
public class hello11 {
    public static void main(String[] args) throws IOException {
        File file = new File("d:" + File.separator + "hello.txt");
        char[] ch = { 'A', 'B', 'C' };
        DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
        for(char c:ch){
            out.writeChar(c);
        }
        out.close();
    }
}
 

【运行结果】:

hello.txt中:A B C

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

import java.io.DataInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
  
public class hello11{ 
    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.DataInputStream;
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 hello12 {
    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();
        sis.close();
        output.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 hello13 {
    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();
    }
}

【运行结果】:

d盘下有一个hello.zip文件,可解压出hello.txt文件。

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

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 hello13 {
    public static void main(String[] args) throws IOException {
        File file = new File("d:" + File.separator + "temp");
        File zipFile = new File("d:" + File.separator + "temp.zip");
        InputStream input = null;
        ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(
                zipFile));
        if(file.isDirectory()){
            File[] fileList=file.listFiles();
            for(int i=0;i<fileList.length;i++){
                input=new FileInputStream(fileList[i]);
                zipout.putNextEntry(new ZipEntry(fileList[i].getName()));
                int temp=0;
                while((temp=input.read())!=(-1)){
                    zipout.write(temp);
                }
                input.close();
            }
        }
        zipout.close();
    }
}

【运行结果】:

先看看需压缩的文件

压缩后

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

import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;
public class hello13 {
    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 hello15 {
    public static void main(String[] args) throws IOException {
        File file = new File("d:" + File.separator + "hello.zip");
        File outFile = new File("d:" + File.separator + "unzip.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();
    }
}

【运行结果】:

可成功解压hello.zip文件为unzip.txt文件。

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

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 hello15 {
    public static void main(String[] args) throws IOException {
        File file = new File("d:" + File.separator + "temp.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+"temp"+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();
        }
    }
}

【运行结果】:

解压缩前的压缩文件:

 

解压后的文件:

 
PushBackInputStream回退流
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
/**
 * 回退流操作
 */
public class hello16 {
    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 hello17 {
    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 hello18 {
    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();
    }
}

【运行结果】:

hello.txt中:??

 

一般情况下产生乱码,都是由于编码不一致的问题。将上面代码中改为byte[] bytes="你好".getBytes("GBK");则hello.txt中结果为:你好,不会乱码。

对象的序列化

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

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

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

import java.io.Serializable;

/**
 * 实现具有序列化能力的类
 */
public class SerializableDemo implements Serializable {
    String name;
    int age;

    public SerializableDemo() {
    }

    public SerializableDemo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "姓名:" + name + "年龄:" + age;
    }
}

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

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

先给一个ObjectOutputStream的例子吧:

import java.io.Serializable;

/**
 * 实现具有序列化能力的类
 */
public class Person implements Serializable{
    String name;
    int age;
    public Person(){
        
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }

    public String toString(){
        return "姓名:"+name+"年龄:"+age;
    }
}
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
 * 示范ObjectOutputStream 
 */
public class ObjectOutputStreamDemo{
    public static void main(String[] agrs) throws FileNotFoundException, IOException{
        File file=new File("d:"+File.separator+"hello.txt");
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(new Person("echo",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);
    }
}

【运行结果】:

 姓名:echo年龄:20

 

到底序列化什么内容呢?

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

Externalizable接口

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

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

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

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * 序列化与反序列化的操作
 */
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 oos = new ObjectOutputStream(new FileOutputStream(
                file));
        oos.writeObject(new PersonB("echo", 20));
        oos.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);
    }
}
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

/**
 * 实现具有序列化能力的类
 */
public class PersonB implements Externalizable {
    String name;
    int age;

    public PersonB() {

    }

    public PersonB(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "姓名:" + name + "年龄:" + age;
    }

    // 复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(this.name);
        out.writeInt(age);
    }

    // 复写这个方法,根据需要读取内容 反序列话的时候需要
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        this.name = (String) in.readObject();
        this.age = in.readInt();

    }
}

【运行结果】:

姓名:echo年龄:20

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

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

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

下面举一个例子:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * lxl_pro
 */

/**
 * 
 */
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 oos = new ObjectOutputStream(new FileOutputStream(
                file));
        oos.writeObject(new PersonC("echo", 20));
        oos.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);
    }
}
import java.io.Serializable;

/**
 * 实现具有序列化能力的类
 */
public class PersonC implements Serializable {
    private transient String name;//用关键字transient说明该属性不想被序列化保存
    int age;

    public PersonC() {

    }

    public PersonC(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "姓名:" + name + "年龄:" + age;
    }
}

【运行结果】:

 姓名:null年龄:20

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

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 序列化一组对象
 */
public class serDemoB {
    public static void main(String[] args) throws Exception {
        PersonC[] per = { new PersonC("echo", 20), new PersonC("snow", 30),
                new PersonC("sunny", 40) };
        ser(per);// 序列化
        Object[] obj = dser();// 反序列化
        for (int i = 0; i < obj.length; i++) {
            PersonC p = (PersonC) obj[i];
            System.out.println(p);
        }
    }

    public static void ser(Object[] obj) throws Exception {
        File file = new File("d:" + File.separator + "hello.txt");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
                file));
        oos.writeObject(obj);
        oos.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;
    }
}
import java.io.Serializable;

/**
 * 实现具有序列化能力的类
 */
public class PersonC implements Serializable {
    private transient String name;// 用关键字transient说明该属性不想被序列化保存
    int age;

    public PersonC() {

    }

    public PersonC(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "姓名:" + name + "年龄:" + age;
    }
}

【运行结果】:

姓名:null年龄:20
姓名:null年龄:30
姓名:null年龄:40

 

原文:http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html ,学习了一遍。

最后做个概述总结:

 

什么是流:

 

 

 

流是一个抽象的概念。当Java程序需要从数据源读取数据时,会开启一个到数据源的流。数据源可以是文件,内存或者网络等。同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件、内存或者网络等。流的创建是为了更方便地处理数据的输入输出。

 

 

 

流分为字节流和字符流。字节流也称为原始数据,需要用户读入后进行相应的编码转换。而字符流的实现是基于自动转换的,读取数据时会把数据按照JVM的默认编码自动转换成字符。

 

 

 

字节流由InputStream和OutputStream处理,而字符流由Reader和Writer处理。Reader和Writer是Java后加入的处理类,出于让数据的处理更方便的目的。

 

 

字节流处理概述:

 

对于字节流处理的类都继承自InputStream和OutputStream这两个抽象类。

 

InputStream提供的最重要的方法是:

read();
read(byte[] b) ;
read(byte[] b, int off, int len) ;

用于从输入流中读取字节。

 

OutputStream提供的最重要的方法是:

write(int b);
write(byte[] b);
write(byte[] b, int off, int len) 

 

用于将字节写入输出流。

 

字节流处理类概述:

 

字节流的处理类有很多,他们都继承自InputStream或者OutputStream抽象类。

 

输入流:

 

先谈谈输入流,输入流中跟数据源直接接触的类有:FileInputStream和ByteArrayInputStream,他们分别实现了从文件或者内存中的字节数组读入数据到输入流。

 

其他的输入流处理类都是装饰类(Decorator模式),下面对他们进行一下简单介绍:

 

BufferedInputStream: 提供了缓冲功能。

DataInputStream: 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。

PipedInputStream: 允许以管道的方式来处理流。当连接到一个PipedOutputStream后,它会读取后者输出到管道的数据。

PushbackInputStream: 允许放回已经读取的数据。

SequenceInputStream: 能对多个inputstream进行顺序处理。

 

输出流:

 

基本上每个输入流类都有一个相应的输出流类,提供相应的输出流处理。

同样,跟数据目的地直接接触的类有:FileOutputStream和ByteArrayOutputStream,前者实现了把数据流写入文件的功能,后者实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray()toString() 获取数据。

 

下面对其它的装饰类做一下简单介绍:

BufferedOutputStream: 提供了缓冲功能的输出流,在写出完成之前要调用flush来保证数据的输出。

DataOutputStream: 数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。

PipedOutputStream: 允许以管道的方式来处理流。可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。

PrintStream: 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。我们经常用到的System.out或者System.err都是PrintStream。

 

字符流处理概述:

 

所有的字符流操作类都继承自Reader或者Writer这两个抽象类。

 

Reader提供的重要方法有:

read(char[] cbuf);
read(char[] cbuf, int off, int len);
read(CharBuffer target);

他们提供了从流中读取数据到字符数组或者CharBuffer的功能。

 

Writer提供的重要方法有:

write(char[] cbuf);
write(char[] cbuf, int off, int len);
write(int c);
write(String str);
write(String str, int off, int len);

他们提供了把字符、字符数组或者字符串写入流中的功能。

 

字符流处理类概述:

 

输入流:

 

跟数据源直接接触的类:

CharArrayReader: 从内存中的字符数组中读入数据,以对数据进行流式读取。

StringReader:从内存中的字符串读入数据,以对数据进行流式读取。

FileReader:从文件中读入数据。注意这里读入数据时会根据JVM的默认编码对数据进行内转换,而不能指定使用的编码。所以当文件使用的编码不是JVM默认编码时,不要使用这种方式。要正确地转码,使用InputStreamReader。

 

装饰类:

BufferedReader:提供缓冲功能,可以读取行:readLine();

LineNumberReader: 提供读取行的控制:getLineNumber()等方法。

InputStreamReader: 字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。

 

输出流:

 

根数据目的相关的类:

CharArrayWriter:把内存中的字符数组写入输出流,输出流的缓冲区会自动增加大小。输出流的数据可以通过一些方法重新获取。

StringWriter: 一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。

FileWriter:把数据写入文件。

 

装饰类:

BufferedWriter:提供缓冲功能。

OutputStreamWriter:字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。

PrintWriter: 向文本输出流打印对象的格式化表示形式。

 

流处理中的其它方法:

 

mark和reset用于重复读取某段的数据,如下代码:

is = new BufferedInputStream(new FileInputStream("res/input.data"));
assertTrue(is.available() > 0);
assertTrue(is.markSupported());

// The read limit has no effect.
is.mark(0);

int first = is.read();
int second = is.read();

is.reset();
int firstAgain = is.read();
int secondAgain = is.read();

assertEquals(first, firstAgain);
assertEquals(second, secondAgain);

Writer或者OutputStream中的flush(): 刷新该流的缓冲,用于确保数据的输出。

 

close(): 关闭流并释放与之关联的所有系统资源。

 

 

 

 

 

 

转载于:https://www.cnblogs.com/echolxl/archive/2013/05/20/3088392.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值