简介
java IO操作中,对数据的传输主要是字节流和字符流2种方式,下面我们分别了解一下字节流和字符流的操作和优缺点
- 由于下面4个都是抽象类,所以代码例子都是使用对应的文件类(FileXXXX)实现的
字节流
顾名思义,就是用字节(byte)的方式传输数据,数据传输自然对应着输入(InputStream)和输出(OutputStream),这里输入和输出对应的对象是服务器(平时,也就是你的电脑),拿文件举例:我们代码中的文字存入磁盘的文件中,就称为输出,反之,则为输入。
OutputStream
- 以字节的方式作为输出
- 是一个抽象类,不能直接实例化,他有众多子类,比如我们常用的FileOutputStream
- 继承了2个接口,分别是Closeable(Closeable又继承了AutoCloseable)、另外一个接口Flushable
- AutoCloseable:可以利用-try()-实现自动关闭资源
- Flushable中的flush()方法可以将内存中缓存的数据强制刷新,比如将内存中缓存的数据,在未关闭钱,强制刷新到文件中。
常用方法
- output.write(int b):输出单个字节
- output.write(byte[] b):输出一组字节数据
- output.write(byte[] b,int off,int len):输出一组数据中的部分字节数据
- 下面是FileOutPutString的使用例子,1.7之后,实现了自动关闭
File file = new File("D:" + File.separator + "file" + File.separator + "out" + File.separator + "bridge.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//文件不存在,会自动创建
String str = " Hello bridge!";
try(OutputStream out = new FileOutputStream(file,true)){ //追加的方式,添加数据
out.write(str.getBytes());
}catch (IOException e){
e.printStackTrace();
}
InputStream
- 以字节的方式读取数据
- 是一个抽象类,不能直接实例化,他有众多子类,比如我们常用的FileInputStream
- 同样的,它也继承了Closeable,但他没有继承Flushable
常用方法
- public int read();返回一个字节,当返回值为-1时,表示结束(输入的实际内容是null)
- public int read(byte[] data);一块一块的读取,返回的值是读取的字节的个数,小于data.length时,则表示读完了
- public int read(byre[],int off, int len);返回真实读取的个数,同上面一样
- public byte[] readAllBytes() throws IOException;:一次性,读取全部数据,当输入数据特别大的时候,谨慎使用
File file = new File("D:" + File.separator + "file" + File.separator + "out" + File.separator + "bridge.txt");
if(!file.exists()){ //如果文件或者目录不存在,提醒用户,目录不存在,这里不会报错
System.out.println("没有找到文件");
return ;
}
//文件不存在,会自动创建
String str = " Hello bridge!";
try(FileInputStream in = new FileInputStream(file)){ //追加的方式,添加数据
byte[] b = new byte[1024];
int length = in.read(b);
System.out.println(new String(b,0, length));
}catch (IOException e){
e.printStackTrace();
}
字符流
使用字符(char)的方式传输数据,输入(Reader)和输出(Writer),字符流是JDK1.1之后才加上的。
Writer
- 实现了4个接口Closeable, Flushable, AutoCloseable,Appendable。前面3个,上面已经介绍过了
- Appendable:表示追加的意思,是jdk1.5之后提出来的,可以将字符序列和值追加到之前的对象,在多线下,需要注意线程安全问题
常用方法
- write(char[] cbuf):基本的方法和OutputSteam一样,只不过换成了char类型
- write(String str):这个比较常用,可以直接存String类型,非常方便
代码
File file = new File("D:" + File.separator + "hello" + File.separator + "bridge.txt");
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs(); // 父目录必须存在
}
Writer out = new FileWriter(file) ;
String str = "正常的内容\r\n" ;
out.write(str);
out.append("我要追加内容……") ; // 追加输出内容
out.close();
Reader
- 实现了3个接口Closeable, AutoCloseable, Readable。前2个上面已经介绍了,Readable:表示读取的来源可以通过字符读取
常用方法
- int read(char[] cbuf):基本的方法和InputSteam一样,只不过换成了char类型
- public long transferTo(Writer out):这个jdk10才有的,目前jdk10普及还不高,可以作为了解
代码
- 如果不写关闭,数据将会在内存中,并不会保存到文件中
File file = new File("D:" + File.separator + "hello" + File.separator + "bridge.txt");
if (file.exists()) { // 文件存在则进行读取
Reader in = new FileReader(file) ;
char data[] = new char[1024];
int len = in.read(data) ;
System.out.println("读取内容:" + new String(data,0,len));
//in.close(); 这里不写的话,内容无法保存到文件中去
}
- 如果不写close(),我们可以使用flush()处理,但是建议关闭资源
File file = new File("D:" + File.separator + "hello" + File.separator + "bridge.txt");
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs(); // 父目录必须存在
}
Writer out = new FileWriter(file) ;
String str = "追加的内容" ;
out.write(str);
out.flush(); // 强制性刷新
总结
- 理解上面4个抽象类,之后的子类就很简单了
- 在处理中文时,字符流比字节流更方便,但是,大部分情况,比如图片、视频传输还是二进制的形式,此时就得使用字节流了
- 接下来,我们可以了解上面4个抽象类的子类了,他们的子类都有父类的特性,针对不同的场景,使用不同的子类。