IO学习笔记

一、输入字节流InputStreamIO 中输入字节流的继承中可以看出:


    InputStream 是所有的输入字节流的父类,它是一个抽象类。


    ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,


    它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,


    与Piped 相关的知识后续单独介绍。


    ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
 
二、输出字节流OutputStream


    OutputStream 是所有的输出字节流的父类,它是一个抽象类。


    ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。


    PipedOutputStream 是向与其它线程共用的管道中写入数据,


    ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。


三、字符输入流Reader


    Reader 是所有的输入字符流的父类,它是一个抽象类。


    CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。


    PipedReader 是从与其它线程共用的管道中读取数据。


    BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。


    FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。


    InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、


    常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。


    Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。
 
四、字符输出流Writer


    Writer 是所有的输出字符流的父类,它是一个抽象类。


    CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。


    PipedWriter 是向与其它线程共用的管道中写入数据,BufferedWriter 是一个装饰器为Writer 提供缓冲功能。


    PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。


    OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。


    功能和使用和OutputStream 极其类似。


五、字符流与字节流转换


    转换流的特点:


    其是字符流和字节流之间的桥梁


    可对读取到的字节数据经过指定编码转换成字符


    可对读取到的字符数据经过指定编码转换成字节


何时使用转换流?


    1.当字节和字符之间有转换动作时;


    2.流操作的数据需要编码或解码时。


具体的对象体现:


    1.InputStreamReader:字节到字符的桥梁


    2.OutputStreamWriter:字符到字节的桥梁


    这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。


 
六、File类


    File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。


    File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,


    判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。  


七、RandomAccessFile类


    该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。


    该对象特点:


    1.该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。


    2.该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)


    3.注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。


案例1:创建一个新文件


import java.io.*;
class hello{
    public static void main(String[] args) {
        File f=new File("D:\\hello.txt");
        try{
            f.createNewFile();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}


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


案例2:File类的两个常量


import java.io.*;
class hello{
    public static void main(String[] args) {
        System.out.println(File.separator);
        System.out.println(File.pathSeparator);
    }
}
运行结果:\


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


现在我们使用File类中的常量改写上面的代码:


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator+"hello.txt";
        File f=new File(fileName);
        try{
            f.createNewFile();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}


没有多写多少代码,所以建议使用File类中的常量。


删除一个文件


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator+"hello.txt";
        File f=new File(fileName);
        if(f.exists()){
            f.delete();
        }else{
            System.out.println("文件不存在");
        }
         
    }
}


创建一个文件夹


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator+"hello";
        File f=new File(fileName);
        f.mkdir();
    }
}


运行结果:D盘下多了一个hello文件夹


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


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator;
        File f=new File(fileName);
        String[] str=f.list();
        for (int i = 0; i < str.length; i++) {
            System.out.println(str[i]);
        }
    }
}
运行结果:


$RECYCLE.BIN


360


360Downloads


360Rec


360SoftMove


Downloads


DriversBackup


MSOCache


Program


Program Files


python


System Volume Information


Tomcat6


var


vod_cache_data


新建文件夹


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


列出指定目录的全部文件(包括隐藏文件):使用listFiles列出指定目录的全部文件,listFiles输出的是完整路径


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator;
        File f=new File(fileName);
        File[] str=f.listFiles();
        for (int i = 0; i < str.length; i++) {
            System.out.println(str[i]);
        }
    }
}


运行结果:


D:\$RECYCLE.BIN


D:\360


D:\360Downloads


D:\360Rec


D:\360SoftMove


D:\Downloads


D:\DriversBackup


D:\eclipse


D:\Lenovo


D:\MSOCache


D:\Program


D:\Program Files


D:\python


D:\System Volume Information


D:\Tomcat6


D:\var


D:\vod_cache_data


D:\新建文件夹


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


 


判断一个指定的路径是否为目录:使用isDirectory判断一个指定的路径是否为目录


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator;
        File f=new File(fileName);
        if(f.isDirectory()){
            System.out.println("YES");
        }else{
            System.out.println("NO");
        }
    }
}


运行结果:YES


搜索指定目录的全部内容


import java.io.*;
class hello{
    public static void main(String[] args) {
        String fileName="D:"+File.separator;
        File f=new File(fileName);
        print(f);
    }
    public static void print(File f){
        if(f!=null){
            if(f.isDirectory()){
                File[] fileArray=f.listFiles();
                if(fileArray!=null){
                    for (int i = 0; i < fileArray.length; i++) {
                        //递归调用
                        print(fileArray[i]);
                    }
                }
            }
            else{
                System.out.println(f);
            }
        }
    }
}


运行结果:


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\framepages\web4welcome_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\help_005fhome_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\help_005fhome_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\home_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\home_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\index_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\index_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\login_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\login_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\modify_005fuser_005finfo_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\modify_005fuser_005finfo_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\register_005fnotify_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\register_005fnotify_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\sign_005fup_jsp.class


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\sign_005fup_jsp.java


D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\transit_jsp.class


……


 


使用RandomAccessFile写入文件:使用RandomAccessFile写入文件


import java.io.*;
class hello{
    public static void main(String[] args) throws IOException {
        String fileName="D:"+File.separator+"hello.txt";
        File f=new File(fileName);
        RandomAccessFile demo=new RandomAccessFile(f,"rw");
        demo.writeBytes("asdsad");
        demo.writeInt(12);
        demo.writeBoolean(true);
        demo.writeChar('A');
        demo.writeFloat(1.21f);
        demo.writeDouble(12.123);
        demo.close();  
    }
}


如果你此时打开hello.txt查看的话,会发现那是乱码。


字节流


向文件中写入字符串:


import java.io.*;
class hello{
    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();
        out.write(b);
        out.close();
    }
}
查看hello.txt会看到“你好”


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


import java.io.*;
class hello{
    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();
    }
}


结果还是:“你好”


向文件中追加新内容:


import java.io.*;
class hello{
    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,true);
        String str="Rollen";
        //String str="\r\nRollen";  可以换行
        byte[] b=str.getBytes();
        for (int i = 0; i < b.length; i++) {
            out.write(b[i]);
        }
        out.close();
    }
}


运行结果:你好Rollen


读取文件内容:字节流读文件内容
 
import java.io.*;
class hello{
    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));
    }
}


运行结果:你好Rollen


Rollen_


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


字节流读文件内容


import java.io.*;
class hello{
    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));
    }
}
运行结果:


读入长度为:18


你好Rollen


Rollen




字符流:向文件中写入数据


现在我们使用字符流


import java.io.*;
class hello{
    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();
    }
}


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


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


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


Writer out =new FileWriter(f,true);


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


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


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


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


/**
 * 字符流
 * 从文件中读出内容
 * */
import java.io.*;
class hello{
    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));
    }
}


运行结果:


读入的长度为:17


内容为hellohello


hello


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


/**
 * 字符流
 * 从文件中读出内容
 * */
import java.io.*;
class hello{
    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 temp=0;
        int count=0;
        while((temp=read.read())!=(-1)){
            ch[count++]=(char)temp;
        }
        read.close();
        System.out.println("内容为"+new String(ch,0,count));
    }
}


运行结果:


内容为hellohello


hello


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


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


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


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


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


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


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


首先编写下面的代码:
/**
 * 文件的复制
 * */
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盘看到rollen。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


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


/**
 * 将字节输入流变为字符输入流
 * */
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));
        char[] b=new char[100];
        int len=read.read(b);
        System.out.println(new String(b,0,len));
        read.close();
    }
}


运行结果:hello


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


ByteArrayInputStream 主要将内容写入内容


ByteArrayOutputStream  主要将内容从内存输出


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


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


运行结果:


rollenholt


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


管道流


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


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 , Rollen";
        try{
            out.write(message.getBytes());
        }catch (Exception e) {
            e.printStackTrace();
        }try{
            out.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
/**
 * 接受消息类
 * */
class Recive implements Runnable{
    private PipedInputStream input=null;
    public Recive(){
        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();
        Recive recive=new Recive();
        try{
//管道连接
            send.getOut().connect(recive.getInput());
        }catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(send).start();
        new Thread(recive).start();
    }
}
运行结果:


接受的内容为 hello , Rollen


打印流


/**
 * 使用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("Rollen");
        print.close();
    }
}


运行结果:


true


Rollen


当然也可以格式化输出


/**
 * 使用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="Rollen";
        int age=20;
        print.printf("姓名:%s. 年龄:%d.",name,age);
        print.close();
    }
}


运行结果:


姓名:Rollen. 年龄:20.


 


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


运行结果:


hello


 


输入输出重定向


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


运行结果:


eclipse的控制台输出的是hello。然后当我们查看d盘下面的hello.txt文件的时候,会在里面看到:这些内容在文件中才能看到哦!


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
 
/**
 * System.err重定向 这个例子也提示我们可以使用这种方法保存错误信息
 * */
public class systemErr{
    public static void main(String[] args){
        File file = new File("d:" + File.separator + "hello.txt");
        System.err.println("这些在控制台输出");
        try{
            System.setErr(new PrintStream(new FileOutputStream(file)));
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }
        System.err.println("这些在文件中才能看到哦!");
    }
}


运行结果:


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


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
 
/**
 * System.in重定向
 * */
public class systemIn{
    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(FileNotFoundException e){
                e.printStackTrace();
            }
            byte[] bytes = new byte[1024];
            int len = 0;
            try{
                len = System.in.read(bytes);
            }catch(IOException e){
                e.printStackTrace();
            }
            System.out.println("读入的内容为:" + new String(bytes, 0, len));
        }
    }
}


【运行结果】:


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


 


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个字节,有点搞不懂。


不过结果肯定是正确的,我只是提出我的一个疑问而已。


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


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();
    }
}
运行结果


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




接下来看看压缩之后的:




大家自然想到,既然能压缩,自然能解压缩,在谈解压缩之前,我们会用到一个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();
    }
}
运行结果:


解压缩之前:




这个压缩文件还是175字节


解压之后产生:






又回到了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();
        }
    }
}
运行结果:


被解压的文件:


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


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





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值