文章目录
流操作简介
File类不支持文件内容处理,如果要处理文件内容,必须要通过流的操作模式来完成。流分为输入流和输出流。
在java.io包中,流分为两种:字节流与字符流
- 字节流(byte):InputStream、OutputStream
- 字符流(char):Reader、Writer
字节流与字符流操作的本质区别只有一个:字节流是原生的操作,而字符流是经过处理后的操作。
一般使用字节流(无论是网络传输还是磁盘数据保存均以字节为单位)。而所有磁盘中的数据必须先读取到内存后才能进行操作,而内存中会帮助我们把字节变为字符。所以一般只有处理中文文本时才会用到字符流。
不管使用的是字节流还是字符流,其基本的操作流程几乎是一样的,以文件操作为例。
- 根据文件路径创建File类对象 ;
- 根据字节流或字符流的子类实例化父类对象 ;
- 进行数据的读取或写入操作
- 关闭流(close())。
对于IO操作属于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)最后必须要进行关闭。
字节输出流(OutputStream)
OutputStream类的定义结构:
public abstract class OutputStream implements Closeable, Flushable
OutputStream类实现了Closeable,Flushable两个接口,这两个接口中的方法:
1. Closeable: public void close() throws IOException;
2. Flushable: public void flush() throws IOException;
在OutputStream类中还定义有其他方法:
1. 将给定的字节数组内容全部输出:public void write(byte b[]) throws IOException
2. 将部分字节数组内容输出:public void write(byte b[], int off, int len) throws IOException
3. 输出单个字节:public abstract void write(int b) throws IOException;
由于OutputStream是一个抽象类,所以要想为父类实例化,就必须要使用子类(如果要进行文件的操作,可以使用FileOutputStream),这个类的构造方法如下:
- 接收File类(覆盖):public FileOutputStream(File file) throws FileNotFoundException
- 接收File类(追加):public FileOutputStream(File file, boolean append)
范例:实现文件的内容输出
import java.io.*;
import java.io.File;
import java.util.Date;
public class Test {
public static void main(String[] args) {
File file = new File("C:Users" + File.separator + "Administrator"
+ File.separator + "Desktop"+File.separator+"Test.txt");
OutputStream out= null;
try {
// out = new FileOutputStream(file);//文本覆盖
out = new FileOutputStream(file,true);//文本追加
String msg="hello HL";
try {
//out.write(msg.getBytes());//文本全部输出
out.write(msg.getBytes(),1,3);//文本部分输出(可能会出现乱码问题)
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
当使用FileOutputStream进行文本内容输出时,只要文件的父路径存在,FileOutputStream会自动创建文件。
AutoCloseable自动关闭支持
从JDk1.7开始追加了一个AutoCloseable接口,这个接口的主要目的是自动进行关闭处理,但是这种处理一般不好用,因为使用它必须结合try…catch
范例:观察AutoCloseable接口使用
class Msg implements AutoCloseable{
void print(){
System.out.println("就随便输出一下....");
}
@Override
public void close() throws Exception {
System.out.println("auto close....");
}
}
public class Test {
public static void main(String[] args) {
try (Msg msg=new Msg()){
msg.print();
}catch (Exception e){
}
}
}
因为语法结构比较混乱,所以还是推荐大家使用close方法手工关闭资源~
字节输入流(InputStream)
InputStream类的定义如下:
public abstract class InputStream implements Closeable
在InputStream类中提供有如下方法:
1.输入
public int read(byte b[]) throws IOException
返回值:
1.如果开辟的字节数组大小大于读取的数据大小,则返回的就是读取个数
2.如果要读取的数据大于数组的内容,那么这个时候返回的就是数组长度
3.如果没有数据了还在读,则返回-1(即数据已经读取完毕)
2.读取单个字节
public abstract int read() throws IOException//每次读取一个字节的内容,直到没有数据了返回-1:
同OutputStream的使用一样,InputStream是一个抽象类,如果要对其实例化,同样也需要使用子类。如果要对文件进行处理,则使用FileInputStream类。
范例:实现文件信息的读取
import java.io.*;
import java.io.File;
import java.util.Date;
public class Test {
public static void main(String[] args)throws IOException {
File file = new File("C:Users" + File.separator + "Administrator"
+ File.separator + "Desktop"+File.separator+"Test.txt");
InputStream input=new FileInputStream(file);
byte[] b=new byte[1024];
int ret=input.read(b);
System.out.println(ret);
System.out.println(new String(b,0,ret));//要是字符数组没有被写满,一定要限制输出字符串的区间
input.close();
}
}
运行结果:
字符输出流(Writer)
个类的定义如下:
public abstract class Writer implements Appendable, Closeable, Flushable
字符输出流(与字节输出流相比,字符输出流多了一个可以直接传String类型的方法)
public void write(String str) throws IOException
如果要操作文件使用FileWriter子类。
范例:通过Writer实现输出
import java.io.*;
import java.io.File;
import java.util.Date;
public class Test {
public static void main(String[] args)throws IOException {
File file = new File("C:Users" + File.separator + "Administrator"
+ File.separator + "Desktop"+File.separator+"Test.txt");
Writer writer=new FileWriter(file);
writer.write("hello");
writer.close();
}
}
字符输入流(Reader)
在Reader类中没有方法可以直接读取字符串类型,这个时候只能通过字符数组进行读取操作
如果要操作文件使用FileReader子类。
范例:通过文件读取数据
import java.io.*;
import java.io.File;
import java.util.Date;
public class Test {
public static void main(String[] args)throws IOException {
File file = new File("C:Users" + File.separator + "Administrator"
+ File.separator + "Desktop"+File.separator+"Test.txt");
Reader reader=new FileReader(file);
char[] ch=new char[1024];
int ret=reader.read(ch);
System.out.println(ret);
System.out.println(new String(ch,0,ret));
reader.close();
}
}
字节流&字符流的区别
通过上的学习我们可以发现,使用字节流和字符流从代码形式上区别不大。但是如果从实际开发来讲,字
节流一定是优先考虑的,只有在处理中文时才会考虑字符流。因为所有的字符都需要通过内存缓冲来进行处理。
所有字符流的操作,无论是写入还是输出,数据都先保存在缓存中。我们可以验证一下,就是写一个字符输出流,但是不关闭字符流,运行,你会发现文件里什么也没有被写入,难道是代码错了?不。是你的运行结果此时还在缓冲区里呆着呢,不妨试一下关闭字节流后运行一下,再观察文件中的内容,你要输出到文件中的内容一定就在里面。然后重复上面的操作,在字节流中跑一下,你就立马明白字节流和字符流的区别啦~
除了关闭字符流,也可以使用字符流缓冲区刷新flush()
范例:字符流刷新操作
import java.io.*;
import java.io.File;
import java.util.Date;
public class Test {
public static void main(String[] args)throws IOException {
File file = new File("C:Users" + File.separator + "Administrator"
+ File.separator + "Desktop"+File.separator+"Test.txt");
Writer out=new FileWriter(file);
String msg="hhh";
out.write(msg);
out.flush();
}
}