黑马程序员————java IO系统

时间:2022-07-12 00:31:32

流的概念
大部分程序都需要输入/输出处理,比如从键盘读取数据、向屏幕中输出数据、从文件中读或者向文件中写数据、在一个网络连接上进行读写操作等。在Java中,把这些不同类型的输入、输出源抽象为流(Stream),而其中输入或输出的数据则称为数据流(Data Stream),用统一的接口来表示,从而使程序设计简单明了。
流一般分为输入流(InputStream)和输出流(OutputStream)两类,但这种划分并不是绝对的。比如一个文件,当向其中写数据时,它就是一个输出流;当从其中读取数据时,它就是一个输入流。当然,键盘只是一个输入流,而屏幕则只是一个输出流。

在Java开发环境中,主要是由包java.io中提供的一系列的类和接口来实现输入/输出处理。标准输入/输出处理则是由包java.lang中提供的类来处理的,但这些类又都是从包java.io中的类继承而来。
输入流:数据提供者,可从中读取数据出来
输出流:数据接收者,可往其中写数据

Java中输入输出流有 InputStream/OutputStream和Reader/Writer两部分类。其中前者定义为流设备,可将系统中任何设备或内存以及内存中的对象当作IO流设备,它们实现最底层的基本操作;而后者定义为流设备的读写器,他们实现对前者的读写功能。

 

File类
每个File类对象都表示一个文件或目录。调用他可以获得该文件或目录的属性,完成对文件或目录的常用管理操作,如创建、删除文件等。但File类不支持从文件读取数据或向文件里写数据。
File(String pathname) 
File f=new File(“c:\\data\\temp.dat”);
File f=new File(“data”);
File f=new File(“temp.dat”);

File(String parent, String child) 
File f=new File(“c:\\data” ,“temp.dat”);
File f=new File(“data ” ,“ temp.dat”);

File(File parent, String child) 
File f1 =new File(“c:\\data”) ;
File f2 =new File(f1 ,“temp.dat”);

常用文件操作 
canRead() 返回文件是否可读
canWrite() 返回文件是否可写
delete() 从文件系统内删除该文件
exists() 判断文件是否存在
getAbsulutePath() 返回文件的完整路径
getName() 返回文件名称
getParent() 返回文件父目录路径
getParentFile() 返回文件所在的文件夹的路径
getPath() 返回文件的潜在相对路径
isDirectory() 判断该路径指示的是否是文件夹
isFile() 判断该路径指示的是否是文件
length() 返回文件长度
list() 返回文件列表
mkdir() 创建目录
createNewFile() 当文件不存在的时候生成空文件

文件输入输出流 
FileInputStream类和FileOutputStream类的构造函数是创建一个输入输出的对象,通过引用该对象的读写方法,来完成对文件的输入输出操作。在构造函数中,需要指定与所创建的输入输出对象相连接的文件。当然,要构造一个FileInputStream对象,所连接的文件必须存在而且是可读的;构造一个FileOutputStream对象如果输出文件已经存在且可写,该文件内容会被新的输出所覆盖。

读写文件中的基本数据类型
DataInputStream和DataOutputStream分别实现了java.io包中的DataInput和DataOutput接口,能够读写java基本数据类型的数据和unicode编码格式的字符串。他们是从FilterStream继承过来的,这两个流不能单独直接使用,必须和其他流配合使用。
FileInputStream是实体流,也就是真实做事情的流,用来读文件的。使用该类创建对象时,系统会自动将需要读的文件转换成该类的流对象,你可以直接读取。DataInputStream是装饰流,必须建立在其他实体流的基础之上

例子:

import java.io.*;   public class DataStreamTest{    public static void main(String[] args) throws Exception {       FileOutputStream fos = new FileOutputStream("count.txt");       BufferedOutputStream bos = new BufferedOutputStream(fos);       DataOutputStream dos = new DataOutputStream(bos);       dos.writeUTF("ab中国");       dos.writeBytes("ab中国");       dos.writeChars("ab中国");       dos.close(); //只要关闭最上层流对象,下层的流对象也会关闭         FileInputStream fis = new FileInputStream("count.txt");      BufferedInputStream bis = new BufferedInputStream(fis);      DataInputStream dis = new DataInputStream(bis);      System.out.pritnln(dos.readUTF());      dis.close();    } }

读写文件中的对象类型
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。readObject 方法用于从流读取对象,writeObject方法用于把对象写入流。只有支持 java.io.Serializable 或 java.io.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.util.Date;
import java.math.BigDecimal;
public class AccountSave2 {
  private static String _FILE_NAME = "user";
  public void readObject(String file_name){
   File file=new File(file_name);
   try {
    FileInputStream fis=new FileInputStream(file);
    ObjectInputStream ois=new ObjectInputStream(fis);
    User user = (User)ois.readObject();
    System.out.println(user.toString());
   } catch (FileNotFoundException e) {
    e.printStackTrace();
   } catch (IOException e) {
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    e.printStackTrace();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
  
  public void writeObject(String file_name, User user){  
   File file=new File(file_name);
   if(!file.exists()){
    try {
     file.createNewFile();
     FileOutputStream fos=new FileOutputStream(file);
     ObjectOutputStream oos=new ObjectOutputStream(fos);
     oos.writeObject(user);
     oos.close();
    } catch (IOException e) {
     e.printStackTrace();
    }  catch (Exception e) {
                     e.printStackTrace();
                    }
   }
       
  }
  
 public static void main(String[] args) {
  AccountSave2 rwfo=new AccountSave2();
  User usr = new User(12345, "杨阿方", "111111", new Date(), new BigDecimal(9.9));
  rwfo.writeObject(_FILE_NAME,usr);
  rwfo.readObject(_FILE_NAME);
 }
}

  class User implements java.io.Serializable {
    private int account_id;  //帐户
    private String uname;  //姓名
    private String pwd;  //密码
    private Date createDate;  //创建日期
    private BigDecimal balance;  //帐户余额

    User(){
    }

    User(int account_id, String uname, String pwd, Date createDate, BigDecimal balance){
      this.account_id = account_id;
      this.uname = uname;
      this.pwd = pwd;
      this.createDate = createDate;
      this.balance = balance;
    }

    public String toString(){
      StringBuffer sb = new StringBuffer();
      sb.append("帐户:"+account_id+"\r\n");
      sb.append("姓名:"+uname+"\r\n");
      sb.append("密码:"+pwd+"\r\n");
      sb.append("创建日期:"+createDate+"\r\n");
      sb.append("帐户余额:"+balance+"\r\n");
      return sb.toString();
    }

  }

随机文件的读取 
在生成一个随机文件对象时,除了要指明文件对象和文件名之外,还需要指明访问文件的模式。
RandomAccessFile(File file, String mode) 
 RandomAccessFile(String name, String mode)  
mode 的取值:
“r” 只读. 任何写操作都将抛出IOException。
“rw” 读写. 文件不存在时会创建该文件,文件存在时,原文件内容不变,通过写操作改变文件内容。  
“rws” 同步读写. 等同于读写,但是任何写操作的内容都被直接写入物理文件,包括文件内容和文件属性。
“rwd” 数据同步读写. 等同于读写,但任何内容写操作都直接写到物理文件,但对文件属性内容的修改不是这样。
对于FileInputStream/FileOutputStream、FileReader/FileWriter来说,它们的实例都是顺序访问流,即只能进行顺序读/写。而类RandomAccessFile则允许对文件内容同时完成读和写操作,它直接继承object,并且同时实现了接口DataInput和DataOutput,提供了支持随机文件操作的方法:
 readXXX()或writeXXX():
 如ReadInt(), ReadLine(), WriteChar(), WriteDouble()等。
 int skipBytes(int n):将指针向下移动若干字节
 length():返回文件长度
 long getFilePointer():返回指针当前位置
 void seek(long pos):将指针调到所需位置
例子:
public class Randomfile
{
    public static void main(String args[])
    {
         int data_arr[]={12, 31, 56, 23, 27, 1, 43, 65, 4, 99};
         try
         {
            RandomAccessFile randf=new RandomAccessFile(“temp.dat”);
            for (int i=0; i<data_arr.length; i++)
                 randf.writeInt(data_arr[i]);
            for(int i=data_arr.length-1; i>=0; i--)
            {
                  randf.seek(i*4L);  //int数据占4个字节
                  System.out.println(randf.readInt());
            }
            randf.close();
         }catch (IOException e){
            System.out.println(“File access error: “+e);
         }
    }
}


字节流
字节和字符的区别
字节(byte)是计算机处理的最小数据单位,字符是指我们能够看到的各种文字。1个字节等于8个bit位,每个bit位又0/1两种状态也就是说一个字节可以表示256个状态,计算机里用字节来作为最基本的存储单位。一般来说,英文状态下一个字母或数字(称之为字符)占用一个字节,一个汉字用两个字节表示。在不同的编码方式下一个字符占的字节书不太一样。
在java中,一个字符(String)是一个unicode编码。

字节流由两个类层次结构定义。在顶层有两个抽象类:InputStream 和 OutputStream。
每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件、网络连接、甚至是内存缓冲区。

黑马程序员————java IO系统

 
字符流
字符流类由两个类层次结构定义。顶层有两个抽象类:Reader和Writer。
这些抽象类处理统一编码的字符流。在Java中这些类含有多个具体的子类。

黑马程序员————java IO系统

 
标准流 
标准输入 
    标准输入System.in作为InputStream类的一个实例来实现,可以使用read()和skip(long n)两个方法。read()实现从输入中读一个字节,skip(long n)实现在输入中跳过n个字节。

    控制台输入由从System.in读取数据来完成。为获得属于控制台的字符流,在BufferedReader对象中包装了System.in。BufferedReader支持缓冲输入流,它最常见的构造函数如下:
     BufferedReader(Reader inputReader)
         其中,inputReader是链接被创建的BufferedReader实例的流。Reader是一个抽象类,它的一个具体的子类是InputStreamReader,该子类将字节转换成字符。为获得链接System.in的一个InputStreamReader的对象,使用下面的构造函数:
    InputStreamReader(InputStream inputStream)
    要从BufferedReader读取字符,用read()。
    int read( ) throws IOException
    该方法每次执行都从输入流读取一个字符,然后以整型形式返回。当遇到流的末尾时,它返回-1。可以看到,它要引发一个IOException异常。
    要从BufferedReader读取字符,用readLine()。
    String readLine() throws IOException
    先使用System.in构造InputStreamReader,再构造BufferedReader。
 BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in));


标准输出 
    标准输出System.out是类System的数据成员out,它属于PrintStream类。PrintStream类和OutputStream类的关系是:OutputStream类是一个抽象类,FilterOutputStream是由抽象类OutputStream派生的,PrintStream类又是这个抽象类FilterOutputStream的一个子类。

    
PrintWriter 类
尽管Java允许使用System.out向控制台写数据,但建议仅用于调试程序时。对于实际的程序,Java推荐的向控制台写数据的方法是用PrintWriter流。PrintWriter是基于字符的类,用基于字符的类向控制台写数据使程序更为国际化。
   PrintWriter定义了多个构造函数,我们所用到的一个如下。
PrintWriter(OutputStream outputStream, boolean flushOnNewline)
   这里,outputStream是OutputStream类的对象,flushOnNewline控制Java是否在println( )方法被调用时刷新输出流。如果flushOnNewline为true,刷新自动发生,若为false,则不发生。
   PrintWriter支持所有类型(包括Object)的print()和println()方法,这样,我们就可以像用System.out那样用这些方法。如果遇到不同类型的情况,PrintWriter方法调用对象的toString()方法并打印结果。
   用PrintWriter向外设写数据,指定输出流为System.out,并在每一新行后刷新流。
管道流
管道是不同线程之间直接传输数据的基本手段。一个线程A通过它的输出管道发送数据,另一个线程B把自己的输入管道接到A的输出管道上即可接收到A发送的数据。
1、PipedInputStream类和PipedOutputStream类
PipedInputStream类创建的对象称为一个输入管道,PipedOutputStream类创建的对象称为一个输出管道。输出管道与输入管道连接就形成了一个传输数据的通道。使用注意的管道,用户可以在不同线程之间实现数据共享。
2、PipedInputStream类的构造方法
    (1)PipedInputStream()
    (2)PipedInputStream(PipedOutputStream a)
3、PipedOutputStream类的构造方法
  (1)PipedOutputStream()
  (2)PipedOutputStream(PipedInputStream a)
4、PipedInputStream类的一些方法
    public int read()从管道输入流中读取一字节。字节值被作为0~255之间的一个整数返回,到达流的末尾返回-1。
    public int read(byte b[],int off,int len)
    public void connect(PipedOutputStream a)
    colse()关闭流
5、PipedOutputStream类的方法
 voidclose() Closes this piped output stream and releases any system resources associated with this stream.
 voidconnect(PipedInputStream snk) Connects this piped output stream to a receiver.
 voidflush() Flushes this output stream and forces any buffered output bytes to be written out.
 voidwrite(byte[] b, int off, int len)  Writes len bytes from the specified byte array starting at offset off to this piped output stream.
 voidwrite(int b)  Writes the specified byte to the piped output stream.


其它常用的流
内存的读/写 
   ByteArrayInputStream和ByteArrayOutputStream 
   StringBufferInputStream和StringBufferOutputStream 
顺序输入流 
   SequenceInputStream 把几个输入流顺序连接起来。顺序输入流提供了把若干不同的流统一为同一个流的功能,使得程序变得更加简洁。