Java IO

Java IO整理

参考文献一http://www.cnblogs.com/lich/tag/java%20IO/
参考文献二http://blog.sina.com.cn/s/blog_7ba28b6201011vv0.html
上图

File类

实例一:创建一个新文件
import java.io.File;
import java.io.IOException;

public class Test1 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test.txt");//为增加可移植性,建议使用File.separator
        try {
            f.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
实例二:删除一个指定文件
import java.io.File;

public class Test2 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test.txt");
        if(f.exists()){//判断文件存不存在,如不存在就不用删除了
            f.delete();
        }
    }
}
实例三:综合创建,删除文件的操作
import java.io.File;
import java.io.IOException;
//给定一个路径,如果此文件存在,则删除,如果不存在,则创建
public class Test3 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test.txt");
        if(f.exists()){
            f.delete();
        }else{
            try {
                f.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
实例四:创建一个文件夹
import java.io.File;
//使用mkdir()方法创建一个文件夹
public class Test4 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test");
        f.mkdir();//创建文件夹
    }
}
实例五:列出指定目录的全部文件

如果现在给出了一个目录,则可以直接列出目录中的内容。但是列出的方法在File类中存在两个:

  • 以字符串数组的形式返回:public String[] list()
  • 以File数组的形式返回:public File[] listFiles()
  • 以File数组的形式列出系统所有的根路径,这是一个静态方法:static File[] listRoots()
    操作一:使用list()列出全部内容
import java.io.File;

public class Test5 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator);
        String[] str=f.list();
        for(String s:str){
            System.out.println(s);
        }
    }
}

操作二:使用listFiles()列出

import java.io.File;

public class Test6 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator);
        File[] files=f.listFiles();
        for(File file:files){
            System.out.println(file);
        }
    }
}
实例六:判断一个给定的路径是否是目录
import java.io.File;

public class Test7 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator);
        if(f.isDirectory()){
            System.out.println(f.getPath()+"是目录");
        }else{
            System.out.println(f.getPath()+"不是目录");
        }
    }
}
实例七:列出指定目录的全部内容
import java.io.File;

public class Test8 {
    public static void main(String[] args) {
        File f = new File("d:" + File.separator);
        print(f);
    }
    public static void print(File f) {
        if (f != null) {
            if (f.isDirectory()) {
                File[] files = f.listFiles();
                if (files != null) {
                    for (File file : files) {
                            print(file);
                    }
                }
            } else {
                System.out.println(f);
            }
        }
    }
}

总结:
- File类是在java.io包中唯一与文件本身有关的
- 可以使用File类创建、删除等常见的文件操作
- 在使用File类指定路径的时候一定要注意操作系统间的差异,尽量使用separator进行分割

RandomAccessFile类

之前的File类只是针对文件本身进行操作的,而如果相对文件内容进行操作,则可以使用RandomAccessFile类,此类属于随机读取类,可以随机的读取一个文件中指定位置的数据。
因为在文件中,所有得内容都是按照字节存放的,都有固定的保存位置。

构造函数:
public RandomAccessFile(File file,String mode)throws FileNotFoundException
实例化此类的时候需要传递File类。告诉程序应该操作的是哪个文件,之后有个模式,文件的打开模式,常用的两种模式:
- r:读
- w:写
- rw:读写,如果使用此模式,如果文件不存在,则会自动创建

文件记录指针
- long getFilePointer():返回文件记录指针的当前位置
- void seek(long pos):将文件记录指针定位到pos位置

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Test9 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        RandomAccessFile raf=new RandomAccessFile(f,"rw");//读写模式,如果该路径不存在会自动创建
        String name1="jim";
        int age1 =20;
        String name2="Tom";
        int age2=30;
        raf.writeBytes(name1);
        raf.writeInt(age1);
        raf.writeBytes(name2);
        raf.writeInt(age2);
        raf.close();
    }
}
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Test10 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        RandomAccessFile raf=new RandomAccessFile(f,"r");//以读模式打开
        raf.skipBytes(7);//跳过第一个人的信息
        byte[] bs=new byte[3];
        for(int i=0;i<bs.length;i++){
            bs[i]=raf.readByte();
        }
        String name2=new String(bs);
        int age2=raf.readInt();
        System.out.println(name2+"  "+age2);

        raf.seek(0);//指针回到文件开头,读取第二个人的信息
        for(int i=0;i<bs.length;i++){
            bs[i]=raf.readByte();
        }
        String name1=new String(bs);
        int age1=raf.readInt();
        System.out.println(name1+"  "+age1);
    }
}

字节流和字符流

先来看一下流的概念:
在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。

程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

字节流与字符流

在java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。(这四个都是抽象类)

操作流程
在Java中IO操作也是有相应步骤的,以文件操作为例,主要的操作流程如下:

  • 使用File类打开一个文件
  • 通过字节流或字符流的子类,指定输出的位置
  • 进行读/写操作
  • 关闭输入/输出

IO操作属于资源操作,一定要记得关闭

字节流

字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream

字节输出流:OutputStream
OutputStream是整个IO包中字节输出流的最大父类,此类的定义如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
从以上的定义可以发现,此类是一个抽象类,如果想要使用此类的话,则首先必须通过子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类。通过向上转型之后,可以为OutputStream实例化
Closeable表示可以关闭的操作,因为程序运行到最后肯定要关闭
Flushable:表示刷新,清空内存中的数据
FileOutputStream类的构造方法如下:
public FileOutputStream(File file)throws FileNotFoundException

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//写数据
public class Test11 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        OutputStream out=new FileOutputStream(f);//如果文件不存在会自动创建
        String str="Hello World";
        byte[] b=str.getBytes();
        out.write(b);//因为是字节流,所以要转化成字节数组进行输出
        out.close();
    }
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//也可以一个字节一个字节进行输出
public class Test11 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        OutputStream out=new FileOutputStream(f);//如果文件不存在会自动创建
        String str="Hello World";
        byte[] b=str.getBytes();
        for(int i=0;i<b.length;i++){
            out.write(b[i]);
        }
        out.close();
    }
}

public FileOutputStream(File file,boolean append)throws FileNotFoundException
在构造方法中,如果将append的值设置为true,则表示在文件的末尾追加内容。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Test11 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        OutputStream out=new FileOutputStream(f,true);//追加内容
        String str="\r\nHello World";
        byte[] b=str.getBytes();
        for(int i=0;i<b.length;i++){
            out.write(b[i]);
        }
        out.close();
    }
}
字节输入流:InputStream

既然程序可以向文件中写入内容,则就可以通过InputStream从文件中把内容读取进来,首先来看InputStream类的定义:
public abstract class InputStream extends Object implements Closeable
与OutputStream类一样,InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,就用FileInputStream来实现。
观察FileInputStream类的构造方法:

public FileInputStream(File file)throws FileNotFoundException
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//读文件
public class Test12 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        int len=in.read(b);
        in.close();
        System.out.println(new String(b,0,len));
    }

}

但以上方法是有问题的,用不用开辟这么大的一个字节数组,明显是浪费嘛,我们可以根据文件的大小来定义字节数组的大小,File类中的方法:public long length()

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test13 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[(int) f.length()];
        in.read(b);
        in.close();
        System.out.println(new String(b));
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//我们换种方式,一个字节一个字节读入
public class Test14 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        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(new String(b));
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//但以上情况只适合知道输入文件的大小,不知道的话用如下方法:
public class Test15 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        int temp=0;
        int len=0;
        while((temp=in.read())!=-1){//-1为文件读完的标志
            b[len]=(byte) temp;
            len++;
        }
        in.close();
        System.out.println(new String(b,0,len));
    }
}
字符流

在程序中一个字符等于两个字节,那么java提供了Reader、Writer两个专门操作字符流的类。

字符输出流:Writer

Writer本身是一个字符流的输出类,此类的定义如下:
public abstract class Writer extends Object implements Appendable,Closeable,Flushable
此类本身也是一个抽象类,如果要使用此类,则肯定要使用其子类,此时如果是向文件中写入内容,所以应该使用FileWriter的子类。
FileWriter类的构造方法定义如下:
public FileWriter(File file)throws IOException
字符流的操作比字节流操作好在一点,就是可以直接输出字符串了,不用再像之前那样进行转换操作了。
写文件:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Test16 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Writer out=new FileWriter(f);
        String str="Hello World";
        out.write(str);
        out.close();
    }
}
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//在默认情况下再次输出会覆盖,追加的方法也是在构造函数上加上追加标记
public class Test17 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Writer out=new FileWriter(f,true);//追加
        String str="\r\nHello World";
        out.write(str);
        out.close();
    }
}
字符输入流:Reader

Reader是使用字符的方式从文件中取出数据,Reader类的定义如下:
public abstract class Reader extends Objects implements Readable,Closeable
Reader本身也是抽象类,如果现在要从文件中读取内容,则可以直接使用FileReader子类。
FileReader的构造方法定义如下:
public FileReader(File file)throws FileNotFoundException
以字符数组的形式读取出数据:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Test18 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Reader input=new FileReader(f);
        char[] c=new char[1024];
        int len=input.read(c);
        input.close();
        System.out.println(new String(c,0,len));
    }
}
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
//也可以用循环方式,判断是否读到底
public class Test19 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Reader input=new FileReader(f);
        char[] c=new char[1024];
        int temp=0;
        int len=0;
        while((temp=input.read())!=-1){
            c[len]=(char) temp;
            len++;
        }
        input.close();
        System.out.println(new String(c,0,len));
    }
}

字节流与字符流的区别
字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有哪些不同呢?
字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的
字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

那开发中究竟用字节流好还是用字符流好呢?
在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。

字符-字节转换流

OutputStreamWriter和InputStreamReader
在整个IO包中,实际上就是分为字节流和字符流,但是除了这两个流之外,还存在了一组字节流-字符流的转换类。
OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变成字节流的输出对象。
InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即:将一个字节流的输入对象变成字符流的输入对象。
一般在操作输入输出内容就需要使用字节或字符流,但是有些时候需要将字符流变成字节流的形式,或者将字节流变为字符流的形式,所以,就需要另外一组转换流的操作类。

看一下OutputStreamWriter的构造方法:
public OutputStreamWriter(OutputStream out)

例如,将字节的文件输出流,以字符的形式输出

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class Test20 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Writer out=new OutputStreamWriter(new FileOutputStream(f));
        out.write("Hello World!!!");
        out.close();
    }
}

读得时候也可以用字符流形式读取字节流的对象

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

public class Test21 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Reader input=new InputStreamReader(new FileInputStream(f));
        char[] c=new char[1024];
        int len=input.read(c);
        input.close();
        System.out.println(new String(c,0,len));
    }
}

以上操作只是以文件操作为例,OutputStreamWriter中接受的类型是OutputStream,只要是字节输出流都可以以使用字符的形式操作,InputStreamReader一样。

FileWriter和FileReader的说明
从JDK文档中可以知道FileOutputStream是OutputStream的直接子类。FileInputStream也是InputStream的直接子类,但是在字符流文件的两个操作类却有一些特殊,FileWriter并不直接是Writer的子类,而是OutputStreamWriter的子类,而FileReader也不直接是Reader的子类,而是InputStreamReader的子类,那么从这两个类的继承关系就可以清楚的发现,不管是使用字节流还是字符流实际上最终都是以字节的形式操作输入输出流的。也就是说,传输或者从文件中读取数据的时候,文件里真正保存的数据永远是字节。

内存操作流

ByteArrayInputStream和ByteArrayOutputStream

之前所讲解的程序中,输出和输入都是从文件中来得,当然,也可以将输出的位置设置在内存之上,此时就要使用ByteArrayInputStream、ByteArrayOutputStream来完成输入输出功能了
ByteArrayInputStream的主要功能将内容输入到内存之中
ByteArrayOutputStream的主要功能是将内存中的数据输出
此时应该把内存作为操作点

ByteArrayInputStream类的定义:
public class ByteArrayInputStream extends InputStream
构造方法:
public ByteArrayInputStream(byte[] buf)
接受一个byte数组,实际上内存的输入就是在构造方法上将数据传入到内存中。
ByteArrayOutputStream:输出就是从内存中写出数据
public void write(int b)

以下是以内存操作流完成的一个大小写字母转换的程序:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class Test22 {
    public static void main(String[] args) throws IOException {
        String str="HELLO WORlD!!!";
        InputStream input=new ByteArrayInputStream(str.getBytes());
        OutputStream output=new ByteArrayOutputStream();
        int temp=0;
        while((temp=input.read())!=-1){
            output.write(Character.toLowerCase(temp));
        }
        input.close();
        output.close();
        System.out.println(output.toString());
    }
}

管道流

管道流(线程通信流)
管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream)、管道输入流(PipedInputStream),如果想要进行管道输出,则必须要把输出流连在输入流之上,在PipedOutputStream类上有如下的一个方法用于连接管道:
public void connect(PipedInputStream snk)throws IOException

例子:线程之间用管道流进行通讯

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

class Send implements Runnable{

    private PipedOutputStream pos;//管道输出流
    public Send(){
        pos=new PipedOutputStream();
    }
    @Override
    public void run() {
        String str="Hello World!";
        try {
            pos.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            pos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public PipedOutputStream getPos() {
        return pos;
    }
}

class Receive implements Runnable{

    private PipedInputStream pis;//管道输入流
    public Receive(){
        pis=new PipedInputStream();
    }
    @Override
    public void run() {
        byte[] b=new byte[1024];
        int len=0;
        try {
            len=pis.read(b);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            pis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(new String(b,0,len));
    }
    public PipedInputStream getPis() {
        return pis;
    }
}

public class Test23 {
    public static void main(String[] args) {
        Send send=new Send();
        Receive receive=new Receive();
        try {
            send.getPos().connect(receive.getPis());//连接管道
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(send).start();//启动线程
        new Thread(receive).start();//启动线程
    }
}

打印流

在整个IO包中,打印流是输出信息最方便的类,主要包含字节打印流(PrintStream)和字符打印流(PrintWrite)。打印流提供了非常方便的打印功能,可以打印任何的数据类型,例如:小数、整数、字符串等等。

看一下PrintStream的构造方法:
public PrintStream(OutputStream out)
在PrintStream中定义的构造方法中可以清楚的发现有一个构造方法可以直接接收OutputStream类的实例,这是因为与OutputStream相比起来,PrintStream可以更加方便的输出数据,这就好比将OutputStream类重新包装了一下,使之输出更加方便。

使用PrintStream输出信息

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class Test24 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        PrintStream output=new PrintStream(new FileOutputStream(f));
        output.println("Hello World!");
        output.print("1+1="+2);
        output.close();
    }
}

也就是说此时,实际上是将FileOutputStream类的功能包装了一下,这样的设计在java中称为装饰设计。

类似c语言的printf:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class Test25 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        PrintStream output=new PrintStream(new FileOutputStream(f));
        String name="Jim";
        int age=20;
        float score=90.5f;
        char sex='M';
        output.printf("姓名:%s 年龄:%d 成绩:%f 性别:%c", name,age,score,sex);
        output.close();
    }
}

System对IO的支持

System表示系统类,此类也对IO给予了一定的支持。
public static final PrintStream out 对应系统标准输出,一般是显示器
public static final PrintStream err 错误信息输出
public static final InputStream in 对应着标准输入,一般是键盘

又是由于历史遗留问题 全局变量没有大写~

System.out

使用System.out输出的时候就是将输出的位置定义在了显示器之中。
FileOutputStream是定位在文件里,而System.out是定位在屏幕上。
使用OutputStream完成屏幕上输出(PrintStream是OutputStream的子类)

import java.io.IOException; 
import java.io.OutputStream; 
public class Test26 { 
            public static void main(String[] args) throws IOException { 

          OutputStream out=System.out;
          out.write("Hello World!".getBytes()); 
          out.close();  
       }
}
System.err

System.err表示的错误的标准输出,如果程序中出现了错误的话,则直接使用System.err进行打印输出即可。

public class Test27 {
    public static void main(String[] args) {
        String str="Hello World";
        try{
        int a=Integer.parseInt(str);
        }catch(Exception e){
            System.err.println(e);
        }
    }
}
System.out与System.err的区别
  • System.out和System.err都是PrintStream的实例化对象,而且通过实例代码可以发现,两者都可以输出错误信息,但是一般来讲System.out是将信息显示给用户看,是正常的信息显示,而System.err的信息正好相反是不希望用户看到,会直接在后台打印,是专门显示错误的
  • 一般来讲,如果要想输出错误信息的时候最好不要使用System.out而是直接使用System.err,这一点只能从其概念上划分。
System.in

System.in实际上是一个键盘的输入流,其本身是InputStream类型的对象。那么,此时就可以利用此方式完成从键盘读取数据的功能。

InputStream对应的是输入流,输入流的话肯定可以从指定位置上读取,之前使用的是FileInputStream是从文件中读取的

import java.io.IOException;
import java.io.InputStream;

public class Test28 {
    public static void main(String[] args) throws IOException {
        InputStream in=System.in;
        byte[] b=new byte[1024];
        int len=in.read(b);
        System.out.println(new String(b,0,len));
    }
}

如果不使用byte数组指定长度呢:

import java.io.IOException;
import java.io.InputStream;

public class Test29 {
    public static void main(String[] args) throws IOException {
        InputStream in=System.in;
        StringBuilder buf=new StringBuilder();
        int temp=0;
        while((temp=in.read())!=-1){
            char c=(char) temp;
            if(c=='\n')break;
            buf.append(c);
        }
        in.close();
        System.out.println(buf.toString());
    }
}

但以上代码还是有很大问题的,输入中文的话~,所以最好的方法还是一次性把数据都放在内存了,再一次性全部拿出来,要实现这个功能的话,要用到BufferedReader类

输入输出重定向

System.out、System.err、System.in都有重定向功能,分别是setOut、setErr、setIn方法
System.out重定向

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;

public class Test30 {
    public static void main(String[] args) throws FileNotFoundException {
        File f = new File("d:" + File.separator+"test.txt");
        System.setOut(new PrintStream(f));
        String str="This is a test!";
        System.out.println(str);
    }
}

System.err重定向

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

public class Test31 {
    public static void main(String[] args) {
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        System.setErr(new PrintStream(out));
        System.err.println("Test---------------");
        System.out.println(out.toString());
    }
}

一般不建议修改err的重定向,因为这些信息都不太希望用户看到
System.in重定向

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test32 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        System.setIn(new FileInputStream(f));
        InputStream in=System.in;
        byte[] b=new byte[1024];
        int len=in.read(b);
        in.close();
        System.out.println(new String(b,0,len));
    }
}

BufferReader和Scanner

如果想要接收任意长度的数据,而且避免乱码产生,就可以使用BufferedReader
public class BufferedReader extends Reader
因为输入的数据有可能出现中文,所以,此处使用字符流完成。BufferedReader是从缓冲区之中读取内容,所有的输入的字节数据都将放在缓冲区之中。
System.in本身表示的是InputStream(字节流),现在要求接收的是一个字符流,需要将字节流变成字符流才可以,所以要用InputStreamReader

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test33 {
    public static void main(String[] args) throws IOException {
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        String str=reader.readLine();
        System.out.println(str);
    }
}

在JDK1.5之后Java提供了专门的输入数据类,此类可以完成BufferedReader类的功能,也可以方便的对输入数据进行验证,此类存放在java.util包中
使用Scanner接收键盘的输入数据:

import java.util.Scanner;

public class Test34 {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        String str=s.next();
        System.out.println(str);
    }
}

比直接使用BufferedReader更加方便,但是这个程序是有问题的,如果输入的字符串中存在空格,那么就会截止,如果我们要接收空格的下,将分隔符变成“\n”。

import java.util.Scanner;

public class Test34 {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        s.useDelimiter("\n");//使用分隔符
        String str=s.next();
        System.out.println(str);
    }
}

对象序列化和反序列化

所谓的对象序列化就是将一个对象转换为二进制流,如果一个类的对象要想实现序列化,则该对象所在的类必须实现Serializable接口,在此接口中没有任何的方法,此接口只是作为一个标识,表示本类的对象具备了序列化的能力。

序列化的思想是“冻结”对象状态,传输对象状态(写到磁盘、通过网络传输等等),然后“解冻”状态,重新获得可用的Java对象,所有这些事情的发生有点像魔术,这要归功于ObjectInputStream/ObjectOutputStream类,完全保真的元数据以及程序员愿意用Serializable标识接口标记他们的类,从而“参与”这个过程。

序列化分为两大部分:
序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例,如果某个类能够被序列化,其子类也可以被序列化。声明为static和transient类型的成员数据不能被序列化。因此static代表类的状态,transient代表对象的临时数据。
对象序列化在一下场景使用比较合适:
- 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
- 当你想用套接字在网络上传送对象的时候;
- 当你想通过RMI(Remote Method Invocation 远程方法调用)传输对象的时候;

如果要想实现对象的序列化,则还要依靠ObjectOutputStream类和ObjectInputStream类,前者属于序列化操作,而或者属于反序列化操作。

public class Person implements Serializable {   
    private String name;   
    private int age;   

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

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

    public int getAge() {   
        return age;   
    }   

    public void setAge(int age) {   
        this.age = age;   
    }   

    public String getName() {   
        return name;   
    }   

    public void setName(String name) {   
        this.name = name;   
    }   

}  

下面通过ObjectOutputStream完成序列化操作:

public class ObjectOutputStreamDemo {   
    public static void main(String args[]) throws Exception {   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectOutputStream oos = null;   
        oos = new ObjectOutputStream(new FileOutputStream(file));   
        Person per = new Person("王旭东", 21);   
        oos.writeObject(per);   
        oos.close();   
    }   

}  

对象被实例化之后,就可以通过ObjectInputStream进行反序列化的操作

public class ObjectInputStreamDemo {   
    public static void main(String args[]) throws Exception {   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectInputStream ois = null;   
        ois = new ObjectInputStream(new FileInputStream(file));   
        Object obj = ois.readObject();   
        Person per = (Person) obj;   
        System.out.println(per);   
    }   

}  

以上操作实际上是整个对象进行的序列化操作,如果现在假设类中的某个属性不希望被序列化的话,则使用transient关键字进行声明;

private transient String name;  

由上面可知可以对一个对象序列化,那么因为Object可以接受任意的引用数据类型,所以也可以同时对多个对象一起进行序列化操作,包括数组;

public class SerializableDemo {   
    public static void main(String args[]) throws Exception {   
        Person per[] = { new Person("张三", 30), new Person("李四", 40),new Person("王五", 50) };   
        serializable(per);   
        Person p[] = (Person[]) delSerializable();   
        print(p);   
    }   
    public static void serializable(Object obj) throws Exception {   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectOutputStream oos = null;   
        oos = new ObjectOutputStream(new FileOutputStream(file));   
        oos.writeObject(obj);   
        oos.close();   
    }   
    public static Object delSerializable() throws Exception {   
        Object temp = null;   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectInputStream ois = null;   
        ois = new ObjectInputStream(new FileInputStream(file));   
        temp = ois.readObject();   
        return temp;   
    }   
    public static void print(Person per[]) {   
        for (Person p : per) {   
            System.out.println(p);   
        }   
    }   

}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值