首先得搞清楚两个概念:什么是输入流与输出流?什么是字节流与字符流?
1.是从程序的角度出发。输入是程序得到外部数据,输出是程序向外部传输数据。
2.个人理解字节流与字符流,字节流是按字节读取,字符流实际上是根据指定编码按照字节读取然后将其解码为字符流。得到就是字符流对象。使用字节流可以读取所有文件,而字符流适用于文本文件。
下面进行详细介绍:
一、字节流
字节输出流OutputStream
OutputStream是将内存中的数据写出到文件中
OutputStream:字节输出流,抽象类。是输出字节流的所有类的超类
FileOutputstream 文件输出流 是OutputStream的子类,就针对于写入文件的流
File f1 = new File("C:\\myPicture\\1.txt");
try {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\myPicture\\1.txt");
fileOutputStream.write("你好".getBytes());
fileOutputStream.close();//注意流的关闭
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//以上注意是将“你好”写入"C:\\myPicture\\1.txt"当中。
2.给文件中续写和换行
我们直接newFileOutputStream(file)这样创建对象,写入数据,会覆盖原有的文件,那么我们想在原有的文件中续写内容怎么办呢?
继续查阅FileOutputStream的API。发现在FileOutputStream的构造函数中,可以接受一个boolean类型的值,如果值true,就会在文件末位继续添加。
FileOutputStream fileOutputStream2 = new FileOutputStream("C:\\myPicture\\1.txt",true);
fileOutputStream2.write("张慧".getBytes());
fileOutputStream2.close();//此时1.txt中的内容就变成了“你好张慧”。
IO异常的处理
在前面编写代码中都发生了IO的异常。我们在实际开发中,对异常时如何处理的,我们来演示一下。
publicclassFileOutputStreamDemo3 {
publicstaticvoidmain(String[] args) {
File file =newFile("c:\\file.txt");
//定义FileOutputStream的引用
FileOutputStream fos =null;
try{
//创建FileOutputStream对象
fos=newFileOutputStream(file);
//写出数据
fos.write("abcde".getBytes());
}catch(IOException e) {
System.out.println(e.toString()+"----");
}finally{
//一定要判断fos是否为null,只有不为null时,才可以关闭资源
if(fos !=null){
try{
fos.close();
}catch(IOException e) {
thrownewRuntimeException("");
}}}}}
字节输入流InputStream
InputStream是将文件中的数据读取到内存中。抽象类。它是字节输出流的所有类的超类。
read() ---abstract int 从输入流中读取数据的下一个字节。
read(byte[ ] b)----int从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。
InputStream有很多子类,其中子类FileInputStream可用来读取文件内容。
FileInputStream从文件系统中的某个文件中获得输入字节。
方法 read()与read(byte【】)
read()返回的是当前读取自己的ASCII码值
一个字节一个字节的从文件读取到内存,返回值是每一个字节(当前读取字节)的ASCII值0——255,如果到达流的尾部,则返回为-1,由于中文文字是两个字节,所以这里就会出现乱码问题。如下1.txt里面内容为“你好baby”
FileInputStream fileInputStream = new FileInputStream("C:\\myPicture\\1.txt");
int read = 0;
System.out.println("read----"+read);
while((read=fileInputStream.read())!=-1){
System.out.println("read---"+read);//一串数字
System.out.println((char)read);//不能输出中文,会乱码
}//打印结果为:一串数字。英文为其对应的ASCII值239 187 191 228 189 160 229 165 189 98 97 98 121中文部分其实是两个字节,只要把这些字节去查阅对应的编码表,就能够得到与之对应的字符。API中是否给我们已经提供了读取相应字符的功能流对象,Reader,读取字符流的抽象超类。
read(byte【】)返回的是实际读取的字节数,并将读取的数据存入缓存byte数组里
为了解决中文读取乱码的问题,所以read(byte【】)是一下子读取一定数量的字节。返回值是实际上读取的字节数
FileInputStream fileInputStream = new FileInputStream("C:\\myPicture\\1.txt");
int read = 0;
byte[] b = new byte[1024];//一下子读取1024个字节
while((read=fileInputStream.read(b))!=-1){
System.out.println(new String(b,0,read));
}
fileInputStream.close();//关流
打印结果:你好baby
文件的复制
方法一://一个字节一个自己的读与写,输入流和输出流之间是通过read这个变量进行数据交换的。效率低下
FileInputStream fileInputStream = new FileInputStream("C:\\myPicture\\1.txt");
FileOutputStream fileOutputStream = new FileOutputStream("C:\\myPicture\\a.txt");
int read = 0;
byte[] b = new byte[1024];
while((read=fileInputStream.read())!=-1){
fileOutputStream.write(read);
}
fileInputStream.close();//关流
fileOutputStream.close();
缓冲数组方式复制文件
每读完规定byte数组大小的数据就写入一次,最终不够数组长度的的一次性写入
FileInputStream fileInputStream = new FileInputStream("C:\\myPicture\\1.txt");
FileOutputStream fileOutputStream = new FileOutputStream("C:\\myPicture\\b.txt");
int read = 0;
byte[] b = new byte[1024];
while((read=fileInputStream.read(b))!=-1){
fileOutputStream.write(b);
}
fileInputStream.close();//关流
fileOutputStream.close();
二、字符流
字符输入流Reader
上述程序中我们读取拥有中文的文件时,使用的字节流在读取,那么我们读取到的都是一个一个字节。只要把这些字节去查阅对应的编码表,就能够得到与之对应的字符。API中是否给我们已经提供了读取相应字符的功能流对象,Reader,读取字符流的抽象超类。
read():读取单个字符并返回
read(char[]):将数据读取到数组中,并返回读取的个数。
FileReader类
发现FileInputStream用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用FileReader。
FileReader fileReader = new FileReader("C:\\myPicture\\1.txt");
int read = 0;
byte[] b = new byte[1024];
while ((read=fileReader.read())!=-1) {
System.out.println(read);
System.out.println((char)read);//能输出中文了
}
fileReader.close();
输出结果为每个字符对应的数字和本身的值,中文也能输出。
字符输出流Writer 超类
FileWriter类是其子类
查阅FileOutputStream的API,发现FileOutputStream用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用FileWriter。
打开FileWriter的API介绍。用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。
FileWriter fileWriter = new FileWriter("C:\\myPicture\\b.txt");
fileWriter.write("我们的爱情到这儿刚刚好");
fileWriter.flush();
fileWriter.close();
//此时b.txt里面已经被写入文字了
需要注意的是:
flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。
总结:lIO流的分类
|-字节流
|-字节输入流InputStream抽象类
|-FileInputStream操作文件的字节输入流
|-字节输出流OuputStream抽象类
|-FileOutputStream操作文件的字节输出流
|-字符流
|-字符输入流Reader抽象类
|- InputStreamReader输入操作的转换流
|- FileReader用来操作文件的字符输入流(简便的流)
|-字符输出流Writer抽象类
|- OutputStreamWriter输出操作的转换流
|- FileWriter用来操作文件的字符输出流(简便的流)