乐趣区

关于java:JavaIO流一字节输入流与字符输入流

IO 流详解

一、输出流

字节输出流

FileInputSteam

1、构造方法:
public FileInputStream(File file) {}
public FileInputStream(FileDescriptor fdObj){}
public FileInputStream(String name){}
2、read 办法:
// 每次读取一个字节
public int read(){}

// 读取 b.length 个字节到 byte 数组中
public int read(byte b[]){}

// 从输出流中读取 len 个字节到字节数组中
public int read(byte b[], int off, int len){}
3、文件读取:
1、read()

每次读取一个字节数据,返回字节数,如果达到文件开端,返回 -1。

文本

abc

public static void method_01(String filePath) throws IOException {
  FileInputStream inputStream = null;
  try {inputStream = new FileInputStream(filePath);
        // 每次读取一个字节
    for (int i = 0; i < 4; i++) {int read = inputStream.read();
      System.out.println(read);
    }
  } catch (FileNotFoundException e) {e.printStackTrace();
  } finally {if (null != inputStream) {
      // 敞开 IO 流
      inputStream.close();}
  }
}

执行后果:

97
98
99
-1

从执行后果能够看出,前三次读取到了数据,返回了对应的 ASCII 码,当读取到文件开端的时候,则返回 -1。


2、read(byte[] b)

读入缓冲区的字节总数,如果达到文件开端,则返回 -1。

文本:

abcdefg

申明一个大于实在数据的 byte 数组读取数据。

public static void method_02(String filePath) throws IOException {

  FileInputStream inputStream = null;
  try {inputStream = new FileInputStream(filePath);

    // 申明的长度大于实在数据长度
    byte[] bytes = new byte[20];

    int length = inputStream.read(bytes);

    System.out.println("字节数组长度:" + bytes.length + "读取到的数据字节长度:" + length);

    for (byte b : bytes) {System.out.print(b + "|");
    }
  } catch (FileNotFoundException e) {e.printStackTrace();
  } finally {if (null != inputStream) {inputStream.close();
    }
  }
}

执行后果:

 字节数组长度:20  读取到的数据字节长度:7
97 | 98 | 99 | 100 | 101 | 102 | 103 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 

能够看出,当咱们 byte 数组的长度大于字节数组的实在长度之后,那么前面的空间全副应用 0 做补位,这也恰好反映了另外一个问题,咱们在应用 byte[] 数组读取文件的时候,千万不要说我设置足够大的长度,就能够居安思危进步读取效率,如果遇到小文件,那么也是很容易造成效率低下的。


3、read(byte b[], int off, int len)

读入缓冲区的字节总数,如果读取到文件开端,则返回 -1;

文本:

abcdefg

申明一个固定大小的 byte 数组,循环读取数据

咱们的文本有七个字节,申明了一个 2 个长度的数组,应该循环四次,第五次读取的时候返回 -1。

public static void method_03(String filePath) throws IOException {

  FileInputStream inputStream = null;
  try {inputStream = new FileInputStream(filePath);

    // 申明 2 个长度
    byte[] bytes = new byte[2];

    int i = 0;
    while (i < 5) {int length = inputStream.read(bytes, 0, bytes.length);
      System.out.println("第" + (i + 1) + "次读取,length:" + length);
      System.out.println("开始输入:");
      for (int j = 0; j < length; j++) {System.out.print(bytes[j] + "|");
      }
      System.out.println();
      i++;
    }
  } catch (FileNotFoundException e) {e.printStackTrace();
  } finally {if (null != inputStream) {inputStream.close();
    }
  }
}

执行后果:

 第 1 次读取,length: 2
开始输入:
97 | 98 | 
第 2 次读取,length: 2
开始输入:
99 | 100 | 
第 3 次读取,length: 2
开始输入:
101 | 102 | 
第 4 次读取,length: 1
开始输入:
103 | 
第 5 次读取,length: -1
开始输入:

留神:

可能有的敌人会遇到我之前遇到的问题,他的文本外面写了汉字或者标点符号, 会呈现乱码 ,咱们给文本最初再追加一个中文,并且把每次读取到的 byte 数组转换成 String 进行输入,看会呈现什么状况。

public static void method_03(String filePath) throws IOException {
  FileInputStream inputStream = null;
  try {inputStream = new FileInputStream(filePath);

    byte[] bytes = new byte[2];

    int i = 0;
    while (i < 5) {inputStream.read(bytes, 0, bytes.length);
      
      // 将 byte[] 转换成 string
      String s = new String(bytes, StandardCharsets.UTF_8);
      System.out.println(s);
      i++;
    }
  } catch (FileNotFoundException e) {e.printStackTrace();
  } finally {if (null != inputStream) {inputStream.close();
    }
  }
}

后果:

ab
cd
ef
g�
��

刚开始脑子抽了,感觉这是什么问题,怎么会乱码呢,如果略微上点心的都会发现,中文占 3 个 byte 字节,你用 2 个存储那铁定乱码呀。那么你必定想过那我把数组申明大一点不就好了,如果你这么想过,那你可能还不晓得社会的险恶。

那么到底怎么办呢?真的就没方法了吗?接下来咱们用一个例子来学习如何解决这种问题。

一个????:

将文本中的内容读取进去,输入到控制台。

既然咱们晓得,下面的乱码是因为英文和中文占用的字节数不同引起的,那咱们要是晓得了整个文件占用的字节长度,那么不就一次性能够读取进去了。恰好 FileInputStream 提供了这样一个办法(available),让咱们能够获取到整个文件所占用的字节数。

public static void printConsole(String filePath) throws IOException {

  FileInputStream inputStream = null;
  try {inputStream = new FileInputStream(filePath);

       // 获取到整个文本占用的整个字节数
    int available = inputStream.available();

    // 申明数组
    byte[] bytes = new byte[available];

    // 读取数据
    int readLength = inputStream.read(bytes, 0, available);
    String s = new String(bytes, StandardCharsets.UTF_8);

    System.out.println("读取到的长度:" + readLength + "available:" + available);
    System.out.println("读取到的内容:" + s);
  } catch (FileNotFoundException e) {e.printStackTrace();
  } finally {if (null != inputStream) {inputStream.close();
    }
  }
}

后果:

 读取到的长度:30  available:30
读取到的内容: abcdef 一个程序员的成长 

这样的话,咱们就能够读取到文本中残缺的内容了。只有理解了这些,那么才会理解咱们的写文件下载的时候为什么要判断 读取到的字节数 !=-1 这样的操作,不然真的很难记住。


字符输出流

FileReader

1、构造方法:
public FileReader(String fileName){};

public FileReader(File file){};

public FileReader(FileDescriptor fd){};
2、read 办法:
public int read(){};

public int read(char cbuf[], int offset, int length){};

public int read(char cbuf[]){};
3、文件读取:

FileReader 的 read 办法读取进去的是一个独立的字符(char),所以面对英文和中文的混合,咱们不会因为占用字节的不同从而导致呈现乱码的状况。

文本:

abcdef 一个程序员的成长 

读取内容的代码:

public static void method_01(String filePath) throws IOException {

  FileReader fr = null;
  try {fr = new FileReader(filePath);

    int c;
    // 每次读取一个字符,等于 - 1 即示意文件读取到开端
    while ((c = fr.read()) != -1) {System.out.println((char) c);
    }
  } catch (FileNotFoundException e) {e.printStackTrace();
  } finally {if (null != fr) {fr.close();
    }
  }

后果:

a
b
c
d
e
f
一
个
程
序
员
的
成
长 

依据后果能够看出,read() 读取进去的每次就是一个独自的字符,那么另外两个 read 办法跟字节流读取都是一样的。

更多内容请关注微信公众号:

退出移动版