1.流的分类
(1)流按照是否直接与特定地方(如磁盘、内存、设备、网络)连接,分为节点流和处理流。
节点流:直接从一个特定的地方(节点)读写数据。
处理流:包裹在节点流上,处理流的构造方法总是带一个其他的流的对象作为参数。
(2)流按照方向分为:输入流和输出流
输入流:从外界进入到程序的方向,用来读取外界的数据。
输出流:从程序发送到外界的方向,用来写出数据到外界。
2.常用的流
(1)InputStream和OutputStream
InputStream是所有字节输入流的父类,OutputStream是所有字节输出流的父类。
(2)文件流FileInputStream和FileOutputStream,是文件字节输入流和文件字节输出流。
FileOutputStream按字节读取文件操作
/**
* java.io.FileOutputStream
* 文件字节输出流,是一个低级流
* 用于向文件中写入字节
* @author zc
*/
public class T01FileOutputStream {
public static void main(String[] args) {
File file=new File("fos.txt");
try {
//如果文件不存在,fos会创建,默认会覆盖写操作,源文件中内容全部清除
/*
* FileOutputStream默认的构造方法是默认写操作,即:
* 若要写出的文件已经存在,会先将该文件中的原有数据全部清除,
* 然后在通过该流写出新的数据
* */
FileOutputStream fos=new FileOutputStream(file);
fos.write("简单点".getBytes());
/*
* 追加写操作,该构造方法需要传入第二个参数,该参数为一个boolean值,若
* 该值为true,则具有追加写操作的能力,那么通过该流写出的内容会被追加到该问价你的末尾
* */
FileOutputStream fos2=new FileOutputStream(file,true);
fos2.write("第二次写".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileInputStream按字节读取文件操作
public class T02FileInputStream {
public static void main(String[] args) {
//java.io.FileNotFoundException: fos.txt (系统找不到指定的文件。)如果文件不存在
File file=new File("fos.txt");
try {
FileInputStream fis=new FileInputStream(file);
byte[] b=new byte[24];
int len;//len为每次读取到的长度,读的内容存放在b里
while((len=fis.read(b))!=-1){
System.out.println(new String(b,0,len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
FileInputStream和FileOutputStream联合实现文件按字节复制操作
public class T03FileCopy {
public static void main(String[] args) {
FileOutputStream fos=null;
FileInputStream fis=null;
try {
fos=new FileOutputStream(new File("myoutput_copy.txt"));
fis=new FileInputStream(new File("fos.txt"));
byte[] b=new byte[24];
int len;
while((len=fis.read(b))!=-1){
fos.write(b,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(3)缓冲流是一种处理流,在读写操作时,使用缓冲流可以在内存中缓冲一些数据,一次性写出,减少写出次数,从而达到调读写效率的目的。
BufferedInputStream:字节缓冲输入流 BufferedOutputStream():字节缓冲输出流 BufferedReader():字符缓冲输入流 BufferedWriter():字符缓冲输出流
public class T04Buffered {
public static void main(String[] args) {
File src=new File("myemp.txt");
File desc=new File("myemp_copy.txt");
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
fis=new FileInputStream(src);
fos=new FileOutputStream(desc);
//高级流关了,会自动关闭低级流
/*
* 缓冲流内部维护了一个缓冲区,当我们调用下面read()方法读取一个字节时,实际上
* 缓冲流让fis读取一组字节并存入到缓冲流自身内部的字节数组中,然后将第一个字节返回.
* 当我们再次调用read()方法
* 读取一个字节时,缓冲流会将字节数组中第二个字节返回,
* 以此类推,直到该数组中所有字节都被读取过后才会再次读取一组字节
* 所以实际上还是通过提高每次读取数据的数量来减少读取的次数提高的读取效率
*
* */
bis=new BufferedInputStream(fis);
bos=new BufferedOutputStream(fos);
byte[] b=new byte[1024];
int len;
while((len=bis.read(b))!=-1){
bos.write(b,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
BufferedOutputStream的flush方法
使用缓冲输出流可以提高写出效率,但是这也存在着一个问题,就是写出数据缺乏即时性。有时我们需要在执行完某些写出操作后,就希望将这些数据确实写出,而非在缓冲区中保存直到缓冲区满后才写出。这时我们可以使用缓冲流的一个方法flush。
/**
* @author zc
*/
public class T05BufferedFlush {
public static void main(String[] args) {
/*
* 通过缓冲输出流写出的字节并不会立刻被写入文件,
* 会先存入其内部的字节数组,知道该数组满了,
* 才会一次性写出所有数据,这样做等同于提高写出数据量
* 减少写出次数提高写出效率
*
* flush方法可以强制将缓冲区已有的数据一次性写出,
* 这样可以提高及时性,但是频繁操作会导致写出次数提高降低写出效率
* */
BufferedOutputStream bos=null;
FileOutputStream fos=null;
File file=new File("flush.txt");
try {
fos=new FileOutputStream(file);
bos=new BufferedOutputStream(fos);
bos.write("我爱中国".getBytes());
//添加flush会强制输出缓存中的内容
bos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}