1.流的概念
在程序中,所有的数据都是以流的形式进行传输和保存的,当程序需要数据的时候要使用输入流读取数据,而当程序需要保存数据时要使用输出流写数据
2.字节流和字符流
字节流:处理单元为1个字节,操作字节和字节数组,在字节流中输出数据用OutputStream,输入使用InputStream
字符流:处理单元为由2个字节组成的Unicode字符,操作字符、字符数组或字符串,在字符流中输出流用Writer,输入流用Reader
二者关系:字符流是Java虚拟机将字节流转化为2个字节的Unicode字符为单位的字符组成的,所以它对多国语言支持性比较好,如果是音频文件、图片、歌曲,就用字节流,如果是关系到中文(文本)的,用字符流好点
区别:1.字节流在操作的时候本身不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的
2.字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲 区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容
3.在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成的,而字符是只有在缓冲区(内存)中才会形成的,所以 使用字节的操作是最多的
4.类常见操作
操作步骤,以文件操作为例,主要流程如下:
1.使用File类打开一个文件
2.通过字节流或字符流的子类,指定输出的位置
3.进行读/写操作
4.关闭输入/输出
4.1 OutputStream类
OutputStream是整个IO包中字节输出流的最大父类,此类的定义如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
从以上的定义可以发现,此类是一个抽象类,如果想要使用此类的话,则首先必须通过子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类。
public void Test1() throws IOException {
File f=new File("d:"+ File.separator+"test.txt");//File.separator 路径分隔符号
OutputStream os=new FileOutputStream(f);//如果文件不存在,会自动创建
String str="hello world!";
byte[] b= str.getBytes(); //因为是字节流,所以要转化为字节数组进行输出
os.write(b);
os.close();
}
也可一个字节一个字节写
public void Test2() throws IOException {
File f=new File("d:"+File.separator+"test.txt");
OutputStream os=new FileOutputStream(f,true);//以追加的方式往文件写数据
String str="append";
byte[] b=str.getBytes();
for(int i=0;i<b.length;i++){//一个一个字节进行输出
os.write(b[i]);
}
os.close();
}
4.2 InputStream类
public void Test3() throws IOException {
File f = new File("d:" + File.separator + "test.txt");
InputStream is=new FileInputStream(f);
byte[] b=new byte[(int)f.length()];
is.read(b); //读取整个字符数组
is.close();
System.out.println(new String(b));
}
或者一个一个字节读取
public void Test4() throws IOException{
File f=new File("d:"+File.separator+"test.txt");
InputStream is=new FileInputStream(f);
byte[] b=new byte[(int)f.length()];
int len=0;
while(is.read()!=-1){
b[len++]=(byte)is.read();
}
is.close();
System.out.println(new String(b));
}
4.3 Writer类
public void Test5() throws IOException{
File f=new File("d:"+File.separator+"test.txt");
Writer w=new FileWriter(f,true);
String str="hi";
w.write(str);
w.close();
}
4.4 Reader类
public void Test6() throws IOException{
File f=new File("d:"+File.separator+"test.txt");
Reader r=new FileReader(f);
char[] ch=new char[1024];
r.read(ch);
r.close();
System.out.println(new String(ch));
}
5.使用原则
1 、是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )
2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 )
3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )
4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )
5 、网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )
二、按是否格式化输出分:
1 、要格式化输出: PrintStream, PrintWriter
三、按是否要缓冲分:
1 、要缓冲: BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 )
四、按数据格式分:
1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类
2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类
五、按输入输出分:
1 、输入: Reader, InputStream 类型的子类
2 、输出: Writer, OutputStream 类型的子类
六、特殊需要:
1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter
2 、对象输入输出: ObjectInputStream, ObjectOutputStream
3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4 、合并输入: SequenceInputStream
5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要):
首先,考虑最原始的数据格式是什么: 原则四
第二,是输入还是输出:原则五
第三,是否需要转换流:原则六第 1 点
第四,数据来源(去向)是什么:原则一
第五,是否要缓冲:原则三 (特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特殊的输入或输出方法)
第六,是否要格式化输出:原则二
6、是否需要缓冲流 BufferedReader/BufferedWriter