黑马程序员:Java基础总结----字节流&InputStream &OutputStream

时间:2023-02-16 18:00:32
黑马程序员:Java基础总结


字节流&InputStream &OutputStream
 ASP.Net+Android+IO开发.Net培训、期待与您交流!


字节流
字节流两个基类:
InputStream , OutputStream

类 OutputStream方法

输出流接受输出字节并将这些字节发送到某个接收器。 
 void write(byte[] b)
          将 b.length 个字节从指定的 byte 数组写入此输出流。
 void write(byte[] b, int off, int len)
          将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b)
          将指定的字节写入此输出流。

类 FileOutputStream

FileOutputStream(String name, boolean append)
          创建一个向具有指定 name 的文件中写入数据的输出文件流。

复制一个图片
            FileOutputStream fos = null;            FileInputStream fis = null;             try            {                  fos = new FileOutputStream("c:\\2.bmp" );                  fis = new FileInputStream("c:\\1.bmp" );
                   byte[] buf = new byte[1024];
                   int len = 0;
                   while((len=fis.read(buf))!=-1)                  {                        fos.write(buf,0,len);                  }             }

类 BufferedOutputStream

BufferedOutputStream(OutputStream out)
          创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

通过字节流的缓冲区完成复制mp3
            BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3" ));            BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3" ));                         int by = 0;
             while((by=bufis.read())!=-1)            {                  bufos.write(by);            }
            bufos.close();            bufis.close();

类 ObjectOutputStream

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

       public static void writeObj()throws IOException      {            ObjectOutputStream oos =                   new ObjectOutputStream(new FileOutputStream("obj.txt" ));
            oos.writeObject( new Person("lisi0" ,399,"kr"));
            oos.close();      }

类 PipedOutputStream

可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态。

PipedOutputStream()
          创建尚未连接到管道输入流的管道输出流。
PipedOutputStream(PipedInputStream snk)
          创建连接到指定管道输入流的管道输出流。
必须使用多线程:            PipedInputStream in = new PipedInputStream();            PipedOutputStream out = new PipedOutputStream();            in.connect(out);
             Read r = new Read(in);             Write w = new Write(out);             new Thread(r).start();             new Thread(w).start();

类 DataOutputStream

可以用于操作基本数据类型的数据的流对象
void writeInt(int v)
          将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。

       public static void readData()throws IOException      {            DataInputStream dis = new DataInputStream(new FileInputStream("data.txt" ));
             int num = dis.readInt();             boolean b = dis.readBoolean();             double d = dis.readDouble();
            System. out.println("num=" +num);            System. out.println("b=" +b);            System. out.println("d=" +d);
            dis.close();      }       public static void writeData()throws IOException      {            DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt" ));
            dos.writeInt(234);            dos.writeBoolean( true);            dos.writeDouble(9887.543);
            dos.close();
            ObjectOutputStream oos = null;            oos.writeObject( new O());
                  }

类 ByteArrayOutputStream

用于操作字节数组的流对象
ByteArrayInputStream :在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭

源设备,
     键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
     控制台 System.out,硬盘FileStream,内存 ArrayStream

byte[] toByteArray()
          创建一个新分配的 byte 数组。
 String toString()
          使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。

       //数据源。      ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD" .getBytes());
       //数据目的      ByteArrayOutputStream bos = new ByteArrayOutputStream();
       int by = 0;
       while((by=bis.read())!=-1)      {             bos.write(by );      }


      System.out.println(bos.size());      System.out.println(bos.toString());
//    bos.writeTo(new FileOutputStream("a.txt"))





类 InputStream方法

 int available()
          返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
(!多线程时读取或跳过的字节数可能小于该数,试图使用此方法的返回值分配缓冲区来实现读取和跳过是不正确的)
返回:可以不受阻塞地从此输入流读取(或跳过)的估计字节数;如果到达输入流末尾,则返回 0
abstract
  int
read()
          从输入流中读取数据的下一个字节。
 int read(byte[] b)
          从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

            FileInputStream fis = new FileInputStream("fos.txt" );            //           int num = fis.available();             byte[] buf = new byte[fis.available()]; //定义一个刚刚好的缓冲区。不用在循环了。
            fis.read(buf);
            System. out.println(new String(buf));
            fis.close();

类 FileInputStream

和InputStream相似

类 BufferedInputStream

字段摘要
protected byte[] buf
          存储数据的内部缓冲区数组。
protected int count
          比缓冲区中最后一个有效字节的索引大 1 的索引。 buf[0] 到 buf[count-1] 的元素包含从底层输入流中获取的缓冲输入数据
protected int marklimit
          调用 mark 方法后,在后续调用 reset 方法失败之前所允许的最大提前读取量。
protected int markpos
          最后一次调用 mark 方法时 pos 字段的值。
protected int pos
          缓冲区中的当前位置。

以下是JDK读取文件的过程
 private void fill() throws IOException {     byte[] buffer = getBufIfOpen();     if (markpos < 0)         pos = 0;            /* no mark: throw away the buffer */     else if (pos >= buffer.length)  /* no room left in buffer */         if (markpos > 0) {  /* can throw away early part of the buffer */             int sz = pos - markpos;             System.arraycopy(buffer, markpos, buffer, 0, sz);             pos = sz;             markpos = 0;         } else if (buffer.length >= marklimit) {             markpos = -1;   /* buffer got too big, invalidate mark */             pos = 0;        /* drop buffer contents */         } else {            /* grow buffer */             int nsz = pos * 2;             if (nsz > marklimit)                 nsz = marklimit;             byte nbuf[] = new byte[nsz];             System.arraycopy(buffer, 0, nbuf, 0, pos);             if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {                 // Can't replace buf if there was an async close.                 // Note: This would need to be changed if fill()                 // is ever made accessible to multiple threads.                 // But for now, the only way CAS can fail is via close.                 // assert buf == null;                 throw new IOException("Stream closed");             }             buffer = nbuf;         }     count = pos;     int n = getInIfOpen().read(buffer, pos, buffer.length - pos);     if (n > 0)         count = n + pos; } public synchronized int read() throws IOException {     if (pos >= count) {         fill();         if (pos >= count)             return -1;     }     return getBufIfOpen()[pos++] & 0xff; }
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。

而在写入数据时,只写该int类型数据的最低8位。


类 ObjectInputStream

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化

ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

类 PipedInputStream

管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏
PipedInputStream(PipedOutputStream src)
          创建 PipedInputStream,使其连接到管道输出流 src

类 DataInputStream

 int readInt()
          参见 DataInput 的 readInt 方法的常规协定。可见有两个大接口DataInput,和DataOutput


类 ByteArrayOutputStream

参见ByteArraysInputStream相似






 ASP.Net+Android+IO开发.Net培训、期待与您交流!