史上最全IO流详解,看着一篇足矣

一:要了解IO,首先了解File类

 File类里面的部分常量,方法java

No.windows

方法或常量数组

类型app

描述dom

1ide

public static final String pathSeparator函数

常量编码

表示路径的分隔符(windows是“;”)spa

2线程

public static final String separator

常量

表示路径的分隔符(windows是“\”)

3

public File(String pathname)

构造

建立File类对象,传入完整路径

4

public boolean createNewFile()throws IOException

普通

建立新文件

5

public boolean delete()

普通

删除文件

6

public boolean exists()

普通

判断文件是否存在

7

public boolean isDirectory()

普通

判断给定的路径是否在一个目录

8

public long length()

普通

返回文件的大小

9

public String[] list()

普通

列出指定目录的所有内容,只是名称

10

public File[] listFiles()

普通

列出指定目录的所有内容,会有路径

11

Public Boolean mkdir()

普通

建立一个目录

12

Public Boolean renameTo(File dest)

普通

为已有的文件重命名

 二:对于File类的基本操做

  a.在E盘建立一个hello.txt文件

File file=new File("e:"+File.separator+"hello.txt");
//不存在则建立新文件
if(!file.exists()){
  file.createNewFile();
}

  b.删除刚刚建立的hello.txt文件

File f=new File("e:"+File.separator+"hello.txt"); 
//若是存在则删除
if(f.exists()){
  f.delete();
}

  c.若是此文件存在,则删除,若是不存在,则建立

File f=new File("e:"+File.separator+"hello.txt");
if(f.exists()){
  f.delete();
}else{
  try {
    f.createNewFile();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

  d.建立文件夹,使用mkdir()方法;

File f=new File("e:"+File.separator+"hello");
f.mkdir();//建立文件夹

  f.列出指定目录的所有文件,使用File里面的2个方法

    public String[] list()

    public File[] listFiles()

//列出e盘下面全部的文件名(使用的是public String[] list())

  File f=new File("e:"+File.separator);
  String[] str=f.list();
  for(String s:str){
  System.out.println(s);
  }

  

//列出e盘下面全部文件的全路径
File f = new File("E:" + File.separator);
File[] files = f.listFiles();
for (File file : files) {
	System.out.println(file);
}

  

  g.判断一个路径是否是文件夹(目录)

File f=new File("e:"+File.separator);
if(f.isDirectory()){
    System.out.println(f.getPath()+"是目录");
}else{
    System.out.println(f.getPath()+"不是目录");
}

  h.列出一个路径下面的所有文件,包括子文件下面的全部文件(使用递归)

public static void main(String[] args) {
    File f = new File("E:" + 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类是针对文件自己进行操做,而要对文件内容进行操做,则可使用RandomAccessFile类(随机读写流)

  构造函数(public RandomAccessFile(File file,String mode)throws FileNotFoundException)

  mode:模式,总共有3种模式

    r:读

    w:写

    rw:读写,若是文件不存在则会自动建立

  1.写入

File f = new File("e:" + File.separator+"test.txt");
RandomAccessFile raf=new RandomAccessFile(f,"rw");//读写模式,若是该路径不存在会自动建立(RandomAccessFile的更多操做请看源码)
String name1="mm";
int age1 =20;
String name2="gg";
int age2=30;
//写入操做 raf.writeBytes(name1); raf.writeInt(age1); raf.writeBytes(name2); raf.writeInt(age2); raf.close();

  2.读取

File f = new File("E:" + File.separator+"test.txt");
RandomAccessFile raf=new RandomAccessFile(f,"r");//以读模式打开
raf.skipBytes(6);//跳过第一我的的信息(第一我的的姓名+年龄+中间的空格为6个字节)
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默认字符编码的是unicode,占两个字节,可是在String换转byte[]时用的getBytes()默认用的编码进行转换,那么就会占3个字节

四:字节流和字符流

   1.首先看下流的概念:在程序中全部的数据都是以流的方式进行传输或保存的,程序须要数据的时候要使用输入流读取数据,而当程序须要将一些数据保存起来的时候,就要    使用输出流完成,程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件

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

    java中提供了专用于输入输出功能的包Java.io,其中包括:
         InputStream,OutputStream,Reader,Writer
         InputStream 和OutputStream,两个是为字节流设计的,主要用来处理字节或二进制对象,
         Reader和 Writer.两个是为字符流(一个字符占两个字节)设计的,主要用来处理字符或字符串.

  3.对于字节流和字符流的理解(重点,看懂此处对于字节流和字符流有很大的帮助):

    a.字符流处理的单元为2个字节的Unicode字符,分别操做字符、字符数组或字符串,而字节流处理单元为1个字节,操做字节和字节数组。因此字符流是由Java虚拟机将字 节转化为2个字节的Unicode字符为单位的字符而成的,因此它对多国语言支持性比较好!若是是音频文件、图片、歌曲,就用字节流好点,若是是关系到中文(文本)的,用字符流好点

    b.全部文件的储存是都是字节(byte)的储存,在磁盘上保留的并非文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,  也是一个字节一个字节地读取以造成字节序列

    c.字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串,字节流提供了处理任何类型的IO操做的功能,但它不能直接处理Unicode字符,而字  符流就能够

    d.字节流是最基本的,全部的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中不少的数据是文本,又提出了字符流的概      念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间经过 InputStreamReader,OutputStreamWriter来关联,其实是经过byte[]和String来关联在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而形成的 

    e.Reader类的read()方法返回类型为int :做为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),若是已到达流的末尾,则返回 -1.inputStream的read()虽然也返回int,但因为此类是面向字节流的,一个字节占8个位,因此返回 0 到 255 范围内的 int 字节值。若是由于已经到达流末尾而没有可用的字节,则返回值-1。所以对于不能用0-255来表示的值就得用字符流来读取!好比说汉字.

  4.操做流程

    1 使用File类打开一个文件

    2 经过字节流或字符流的子类,指定输出的位置

    3 进行读/写操做

    4 关闭输入/输出

    IO操做属于资源操做,必定要记得关闭

   5.字节流操做

    a.字节输入流:OutputStream

     OutputStream是整个IO包中字节输出流的最大父类,此类的定义以下:

     public abstract class OutputStream extends Object implements Closeable,Flushable

     从以上的定义能够发现,此类是一个抽象类,若是想要使用此类的话,则首先必须经过子类实例化对象,那么若是如今要操做的是一个文件,则可使用:                                        FileOutputStream类。经过向上转型以后,能够为OutputStream实例化

       Closeable表示能够关闭的操做,由于程序运行到最后确定要关闭

                 Flushable:表示刷新,清空内存中的数据

                 FileOutputStream类的构造方法以下:

                 public FileOutputStream(File file)throws FileNotFoundException

      写数据:

File f = new File("e:" + File.separator+hello.txt");
OutputStream out=new FileOutputStream(f);//若是文件不存在会自动建立
String str="Hello World";
byte[] b=str.getBytes();
out.write(b);//由于是字节流,因此要转化成字节数组进行输出
out.close();

    也能够一个字节一个字节进行输出,以下:

File f = new File("e:" + File.separator+"hello.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();

  

   以上输出只会进行覆盖,若是要追加的话,请看FileOutputStream类的另外一个构造方法:

   public FileOutputStream(File file,boolean append)throws FileNotFoundException

   在构造方法中,若是将append的值设置为true,则表示在文件的末尾追加内容。

File f = new File("e:" + File.separator+"hello.txt");
OutputStream out=new FileOutputStream(f,true);//追加内容
//\r\n为换行 String str="\r\nHello World"; byte[] b=str.getBytes(); for(int i=0;i<b.length;i++){ out.write(b[i]); } out.close();

 

 

    b.字节输入流:InputStream

    既然程序能够向文件中写入内容,则就能够经过InputStream从文件中把内容读取进来,首先来看InputStream类的定义:

    public abstract class InputStream extends Object implements Closeable

    与OutputStream类同样,InputStream自己也是一个抽象类,必须依靠其子类,若是如今是从文件中读取,就用FileInputStream来实现。

    观察FileInputStream类的构造方法:

    public FileInputStream(File file)throws FileNotFoundException

      读文件:

File f = new File("e:" + File.separator+"hello.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()

File f = new File("e:" + File.separator+"hello.txt");
InputStream in=new FileInputStream(f);
byte[] b=new byte[(int) f.length()];
in.read(b);
in.close();
System.out.println(new String(b));

  一个字节一个字节读入

File f = new File("e:" + File.separator+"hello.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));

  但以上状况只适合知道输入文件的大小,不知道的话用以下方法:

File f = new File("e:" + File.separator+"hello.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));

  

  6.字符流操做

    a.Writer自己是一个字符流的输出类,此类的定义以下:

       public abstract class Writer extends Object implements Appendable,Closeable,Flushable

       此类自己也是一个抽象类,若是要使用此类,则确定要使用其子类,此时若是是向文件中写入内容,因此应该使用FileWriter的子类。

       FileWriter类的构造方法定义以下:

       public FileWriter(File file)throws IOException

       字符流的操做比字节流操做好在一点,就是能够直接输出字符串了,不用再像以前那样进行转换操做了。

    b.写文件

File f = new File("e:" + File.separator+"hello.txt");
Writer out=new FileWriter(f);
String str="Hello World";
out.write(str);
out.close();

  在默认状况下再次输出会覆盖,追加的方法也是在构造函数上加上追加标记

File f = new File("e:" + File.separator+"hello.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

  以字符数组的形式读取出数据:

File f = new File("e:" + File.separator+"hello.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));

  也能够用循环方式,判断是否读到底:

File f = new File("e:" + File.separator+"hello.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));

  

   7.总结:字节流与字符流的区别

    a.字节流在操做的时候自己是不会用到缓冲区(内存)的,是与文件自己直接操做的,而字符流在操做的时候是使用到缓冲区的

    b.字节流在操做文件时,即便不关闭资源(close方法),文件也能输出,可是若是字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,而且可使用flush方法强制进行刷新缓冲区,这时才能在不close的状况下输出内容

  8.使用场景:在全部的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会造成的,因此使用字节的操做是最多  的。(例:若是要java程序实现一个拷贝功能,应该选用字节流进行操做(可能拷贝的是图片),而且采用边读边写的方式(节省内存)。)

 五:字节流和字符流转换

   OutputStreamWriter和InputStreamReader

   OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变成字节流的输出对象。

   InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即:将一个字节流的输入对象变成字符流的输入对象。

  OutputStreamWriter的构造方法:

    public OutputStreamWriter(OutputStream out)

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

File f = new File("e:" + File.separator+"hello.txt");
Writer out=new OutputStreamWriter(new FileOutputStream(f));
out.write("Hello World!!!");
out.close();

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

File f = new File("e:" + File.separator+"hello.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));

  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)

 

  

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输出信息:

File f = new File("e:" + File.separator+"hello.txt");
PrintStream output=new PrintStream(new FileOutputStream(f));
output.println("Hello World!");
output.print("1+1="+2);
output.close();

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

File f = new File("e:" + File.separator+"hello.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();

你要是以为%s %d %f %c太麻烦,能够全用%s代替

 

九:BufferReader和Scanner

若是想要接收任意长度的数据,并且避免乱码产生,就可使用BufferedReader

public class BufferedReader extends Reader

由于输入的数据有可能出现中文,因此,此处使用字符流完成。BufferedReader是从缓冲区之中读取内容,全部的输入的字节数据都将放在缓冲区之中。

System.in自己表示的是InputStream(字节流),如今要求接收的是一个字符流,须要将字节流变成字符流才能够,因此要用InputStreamReader

BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
String str=reader.readLine();
System.out.println(str);

  

在JDK1.5以后Java提供了专门的输入数据类,此类能够完成BufferedReader类的功能,也能够方便的对输入数据进行验证,此类存放在java.util包中

使用Scanner接收键盘的输入数据:

Scanner s=new Scanner(System.in);
String str=s.next();
System.out.println(str);

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

Scanner s=new Scanner(System.in);
s.useDelimiter("\n");//使用分隔符
String str=s.next();
System.out.println(str);
相关文章
相关标签/搜索