【Java】基本字节流输入输出类的使用


基本字节流

1. 基本字节输入输出类结构

Java基本字节流相关实现类

2. 抽象父类:InputStream & OutputStream

InputStream字节输入流:

public abstract class InputStream
    extends Object
    implements Closeable

这个抽象类是表示输入字节流的所有类的超类。需要定义InputStream子类的应用InputStream必须始终提供一种返回输入的下一个字节的方法。

abstract int read()
从输入流读取数据的下一个字节。
int read(byte[] b)
从输入流读取一些字节数,并将它们存储到缓冲区 b 。
int read(byte[] b, int off, int len)
从输入流读取最多 len字节的数据到一个字节数组。

OutputStream字节输出流:

public abstract class OutputStream
    extends Object
    implements Closeable, Flushable

这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。需要定义OutputStream子类的应用OutputStream必须至少提供一个写入一个字节输出的方法。

void write(byte[] b)
将 b.length字节从指定的字节数组写入此输出流。
void write(byte[] b, int off, int len)
从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。
abstract void write(int b)
将指定的字节写入此输出流。

2.1 实现类:字节节点流 FileOutputStream & FileInputStream

  • FileOutputStream类(字节节点输出流):
public class FileOutputStream
    extends OutputStream

核心方法:

void write(int b)
将指定的字节写入此文件输出流。
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。

构造方法:

FileOutputStream(File file)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append)
创建文件输出流以写入由指定的 File对象表示的文件,append==true追加,不覆盖。
FileOutputStream(FileDescriptor fdObj)
创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
FileOutputStream(String name)
创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append)
创建文件输出流以指定的名称写入文件。

示例代码:

public class TestFileOutputStream {
      public static void main(String[] args) throws IOException {
            // 1.输出字节流 OutputStream
            // 2.输出字节节点流,具有实际传输数据的功能,boolean append ==  true不覆盖原文件内容,追加写入
            // 3.路径正确,文件不存在,会自动创建文件
            // 4.使用相对路径,相对于当前项目的路径,寻找路径和文件
            FileOutputStream fos = new  FileOutputStream(".\\files\\target.txt", true);
            
            try {
                  String s = "你";
                  fos.write(s.getBytes()); // 写入中文
                  
                  fos.write(65); // 写入字符
                  fos.write(66);
                  fos.write(67);
                  fos.write('D');
                  byte[] bs = new byte[] {65, 66, 67, 68, 69, 'Z'}; //  写入字符数组
                  fos.write(bs);
                  System.out.println("OK");
            } catch (IOException e) {
                  e.getStackTrace();
            } finally {
                  fos.close();
            }
      }
}
  • FileInputStream类(字节节点输入流):
public class FileInputStream
    extends InputStream

核心方法:

int read()
从该输入流读取一个字节的数据。
int read(byte[] b)
从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件尾部,返回-1
int read(byte[] b, int off, int len)
从该输入流读取最多 len字节的数据为字节数组。

构造方法:

FileInputStream(File file)
通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj)
创建 FileInputStream通过使用文件描述符 fdObj ,其表示在文件系统中的现有连接到一个实际的文件。
FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

示例代码:

public class TestFileInputStream {
      public static void main(String[] args) throws IOException {
            FileInputStream fis = new  FileInputStream(".\\files\\target.txt");
            try {
                  // 逐个字节读入
//                while (true) {
//                      int n = fis.read();
//                      if (n < 0) { // -1, 文件结尾EOF
//                            break;
//                      }
//                      System.out.println((char)n);
//                }
                  
                  // 按照数组读入
                  byte[] bs = new byte[4];
                  while(true) {
                        int count = fis.read(bs); // count:每次读取到的有效字节个数
                        if (count < 0) { // -1, 文件结尾EOF
                              break;
                        }
                        // 读多少个,输出多少个
                        for (int i = 0; i < count; i++) {
                              System.out.print((char)bs[i]);
                        }
                        System.out.println();
                  }
                  
                  //read(bs, off, len); // 读入bs数组中,从off下标开始,每次读入len
                  
            } catch (Exception e) {
                  e.printStackTrace();
            } finally {
                  fis.close();
            }
      }
}

输入输出综合使用场景:

public class TestFileIOcopy {
      public static void main(String[] args) throws IOException {
            // 拷贝一张图片
            FileInputStream fis = new  FileInputStream("C:\\Users\\Administrator\\Desktop\\test.jpg");
            FileOutputStream fos = new  FileOutputStream("files\\new.jpg");
            int data = 0;
            
            try {
                  // 无参的read()返回的是数据
                  while ((data = fis.read()) >= 0) {
                        System.out.println(data);
                        fos.write(data);
                  }
            } finally {
                  fis.close();
                  fos.close();
            }
      }
}

2.2 实现类:字节过滤流(缓冲流)BufferedOutputStream & BufferedInputStream

特点:

  • 提高IO效率,减少访问磁盘次数;
  • 数据存储在缓冲区中,flush是讲缓存区的内容写入文件中,也可以直接close;
public class BufferedOutputStream
    extends FilterOutputStream

public class BufferedInputStream
    extends FilterInputStream

示例演示:

public class TestBufferredOutput {
      public static void main(String[] args) throws IOException {
            // 输出节点流
            FileOutputStream fos = new  FileOutputStream("files\\buffer.txt");
            // 增强节点流:有参构造需要一个字节输出节点流
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            try {
                  // 过滤流的write方法,是先写入到缓冲区数组里
                  bos.write('A');
                  bos.write('B');
                  bos.write('C');
                  // 刷新缓冲区:将缓冲区的数据,或一次性写入文件中,并清空当前缓冲区
                  bos.flush();
                  bos.write('E');
                  // 每次均需刷新缓冲区
                  //bos.flush();
            } catch (Exception e) {
                  e.printStackTrace();
            } finally {
                  // .close() 级联的执行了flush();释放了资源的同时,将缓冲器的数据一次性写入到文件中
                  bos.close();
                  System.out.println("写入OK");
            }
            
            // 输入字节流 - 普通的即可
            FileInputStream fis = new  FileInputStream("files\\buffer.txt");
            //BufferedInputStream bis = new BufferedInputStream(fis);
            byte[] b = new byte[100];
            fis.read(b);
            for (int i = 0; i < b.length; i++) {
                  System.out.println((char)b[i]);
            }
            
            fis.close();
      }
}

2.3 实现类:字节过滤流(对象流)ObjectOutputStream & ObjectInputStream - 【最佳】

public class ObjectOutputStream
    extends OutputStream
    implements ObjectOutput, ObjectStreamConstants

public class ObjectInputStream
    extends InputStream
    implements ObjectInput, ObjectStreamConstants

特点:

  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串功能
  • 增强了读写对象的功能:
    1. Object readObject() // 从流中读取一个对象
    2. void writeObject(Object obj) // 向流中写入一个对象
  • 对象序列化:
    使用流传输对象的过程称为序列化、反序列化。
  1. 必须实现Serializable接口
  2. 对象自身和类中属性都必须序列化(即实现Serializable这个空接口即可,基本数据类型数组可不序列化,引用数据类型必须序列化);
  3. transient 关键字修饰为临时属性,不参与序列化;
  4. 对象的默认序列化机制写入对象的类、类签名和所有非瞬态和非静态字段的值,因此属性不能使用static修饰,否则取的都是最后一次的值(static属于类本身,会影响序列化)。
  5. 序列化对象流读取到文件尾,会抛出 EOFException 异常 - 捕获后停止读取文件
public class TestObjectStream {
      public static void main(String[] args) throws IOException,  ClassNotFoundException {
            // 写
            OutputStream os = new  FileOutputStream("files\\target.txt");
            ObjectOutputStream oos = new ObjectOutputStream(os);
            Student stu = new Student("小明", 12, "男", 100D);
            Student stu1 = new Student("小黑", 13, "男", 60D);
            oos.writeObject(stu); // NotSerializableException: 类实现Serializable接口即可
            oos.writeObject(stu1);
            oos.flush();
            oos.close();
            // 读
            InputStream is = new FileInputStream("files\\target.txt");
            ObjectInputStream ois = new ObjectInputStream(is);
            while (true) {
                  try {
                  Object obj = ois.readObject();
                  System.out.println(obj);
                  } catch (EOFException e) {
                        // 到达文件尾,抛出EOFException文件尾异常
                        break;
                  }
            }
            ois.close();
      }
}
// 对象需要实现序列化
// 属性也需要实现序列化
class Student implements Serializable {
      private static final long serialVersionUID = 1L;
      /*static*/String name; // static为类所有,会影响该属性值变为一个相同的值
      Integer age;
      String sex;
      transient Double score; // transient修饰的属性不参与序列化,均为null
      public Student() {
            super();
      }
      public Student(String name, Integer age, String sex, Double  score) {
            super();
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.score = score;
      }
      @Override
      public String toString() {
            return "Student [name=" + name + ", age=" + age + ", sex="  + sex + ", score=" + score + "]";
      }
}
发布了320 篇原创文章 · 获赞 311 · 访问量 66万+

猜你喜欢

转载自blog.csdn.net/sinat_36184075/article/details/104904947