Java - I/O之字节流和字符流
1. 流的概念
stream即一系列数据,当不同介质之间有数据交互的时候Java就使用流来实现。当建立文件输入流后,这个流就可以用来把数据从硬盘读取到JVM(内存)中。流分为输入流(InputStream)和输出流(OutputStream)。
2. 流的种类
目前我接触到的流主要分为2类,一类是字节流(byte),另一类是字符流(char)。
关系如下:(当看到水印的时候就知道这图我绝对是借鉴的,我的xmind崩了)
2.1字节流
字节流即以字节的方式读取和写入数据。
写入:FileInputStream
读取:FileOutputStream
/*
* 以字节流的形式读取数据
* */
public static void read(File file){
try(FileInputStream fis=new FileInputStream(file)){
byte[] all=new byte[(int)file.length()];
//将数据写入all数组中
fis.read(all);
for(byte b:all){
System.out.println(b);
}
}catch (IOException e){
e.printStackTrace();
}
}
/*
* 以字节流的形式向文件中写入数据
* */
public static void write(File file){
try(FileOutputStream fos=new FileOutputStream(file)){
//1.先判断一下文件路径是否存在,不存在的话新建个相应目录
if(!file.exists()){
//2.如果文件不存在的话找到file的目录,新建
file.getParentFile().mkdirs();
//3.下面这步是根据file创建空白文件,可以不写,因为outputStream在写出的时候只要路径正确,如果没有文件会自动进行创建
file.createNewFile();
}
byte[] words={'a',99};
fos.write(words);
}catch (IOException e){
e.printStackTrace();
}
}
2.1.1数据流
数据流可以直接对文件进行字符串的读写,但是写好的文件需要指定的流进行读取。
数据输入流: DataInputStream
数据输出流: DataOutputStram
/*
* 以数据输入流的形式读取数据
* */
public static void read(File file){
try(FileInputStream fis=new FileInputStream(file);
DataInputStream dis=new DataInputStream(fis)){
int i=dis.readInt();
String str=dis.readUTF();
char c=dis.readChar();
}catch (IOException e){
e.printStackTrace();
}
}
/*
* 以数据输出流的形式向文件中写入数据
* */
public static void write(File file){
try(FileOutputStream fos=new FileOutputStream(file);
DataOutputStream dos=new DataOutputStream(fos); ){
dos.writeInt(123);
dos.writeUTF("This is a string");
dos.writeChar('a');
}catch (IOException e){
e.printStackTrace();
}
}
2.1.2 对象流
对象流指的是可以直接把一个对象以流的形式传输给其他介质。一个对象以流的形式进行传输,叫做序列化。该对象所对应的类必须是实现了Serializable接口。
对象输入流: DataInputStream
对象输出流: DataOutputStream
将进行序列化的对象:
package Obj;
import java.io.Serializable;
public class Dog implements Serializable {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dog(){
}
}
以对象流的形式读写数据
public static void main(String[] args) {
Dog dog=new Dog();
dog.name="小黑";
//准备一个文件用于保存该对象
File f=new File("C:\\File\\test.txt");
try(
//创建对象输出流
FileOutputStream fos=new FileOutputStream(f);
ObjectOutputStream oos=new ObjectOutputStream(fos);
//创建对象输入流
FileInputStream fis=new FileInputStream(f);
ObjectInputStream ois=new ObjectInputStream(fis);
){
//将对象写入文件中
oos.writeObject(dog);
//从文件中读取对象
Dog d=(Dog) ois.readObject();
}catch (IOException | ClassNotFoundException e){
e.printStackTrace();
}
}
2.2字符流
字符流专门用于字符形式读取和写入数据。
字符流读取文件:FileRead
字符流写入文件:FileWrite
/*
* 以字符输入流的形式读取数据
* */
public static void read(File file){
try(FileReader fr=new FileReader(file)){
char[] all=new char[(int)file.length()];
for(char b:all){
System.out.println(b);
}
}catch (IOException e){
e.printStackTrace();
}
}
/*
* 以字符输出的形式向文件中写入数据
* */
public static void write(File file){
try(FileWriter fw=new FileWriter(file)){
String data="abcdefg1234567890";
char[] all=data.toCharArray();
fw.write(all);
}catch (IOException e){
e.printStackTrace();
}
}
2.2.1缓存流
当字节和字符流在进行每一次读写的时候,都会访问硬盘,如果读写的频率比较高,其性能会表现不佳。缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。
缓存读取流:BufferedRead
缓存输出流:PrintWrite
/*
* 以缓存输入流的形式读取数据
* */
public static void read(File file){
try(FileReader fr=new FileReader(file);BufferedReader br=new BufferedReader(fr);){
while(true){
String line=br.readLine();
if(line==null){
break;
}
System.out.println(line);
}
}catch (IOException e){
e.printStackTrace();
}
}
/*
* 以缓存输出的形式向文件中写入数据
* */
public static void write(File file){
try(FileWriter fw=new FileWriter(file);PrintWriter pw=new PrintWriter(fw);){
pw.println("这是一个缓存输出流");
}catch (IOException e){
e.printStackTrace();
}
}
3.编码导致的中文问题
Java采用Unicode的编码形式,写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。而这些中文字符采用的编码方式,都是使用UNICODE. "中"字对应的UNICODE是4E2D,所以在内存中,实际保存的数据就是十六进制的0x4E2D, 也就是十进制的20013。
而在使用字符流读取这些数据时,FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了,而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK,FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替。
/*
* 以InputStreamReader的形式读取数据
* */
public static void read(File file){
try(FileInputStream fis=new FileInputStream(file);InputStreamReader isr=new InputStreamReader(fis, Charset.forName("utf-8"));){
char[] cs=new char[(int)file.length()];
isr.read(cs);
}catch (IOException e){
e.printStackTrace();
}
}