常见流与对象
文件类: File
打印流 PrintStream PrintWriter
管道流 PipInputteStream PipeOutputStream
序列流 SequenceInputStream
对象序列化流 ObjectInputStream ObjectOutputStream
IO流:用于处理设备上的文件
设备:硬盘,内存,键盘录入
IO分类:
1、 根据处理的数据类型不同:字节流和字符流
2、 根据流向不同:输出流和输入流
字符流的由来:因为文件编码的不同,而有了对字符进行高效的字符流对象
原理:其实就是基于字节流去读取字节时,去查了指定的码表。
字节流和字符流的区别:
1、 字节流读取的时候,读到一个字节就返回一个字节。
字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。
2、 字节流可以处理所有类型的数据,如图片, mp3, avi。
而字符流只能处理字符数据。
结论:如果只是处理纯文本数据,就要优先考虑使用字符流,除此之外都要使用字节流。
IO体系
1、 字节流
InputStream(读), OutputStream(写)
2、 字符流
Reader(读), Writer(写)
基本的读写操作:
通常数据都是以文件形式存在
所以就要找到IO体系中可以用于操作文件的流对象
通过名称可以更容易获取该对象。
Reader
|---InputStreamReader
|---FileReader:专门用于处理文件的字符读取流对象
Write
|---OutputStreamWriter
|--FileWriter:专门用于处理文件的字符写入流对象
程序1:将文本数据存储到一个文件中
import java.io.*;
public class Demo
{
public static void main (String[] args)throws Exception
{
FileWriter fw = new FileWriter("Demo.txt");
fw.write("12345678901234567890");
fw.flush();
fw.write("abcdefgABCDEFG");
fw.close();
}
}
清单2:完整的异常处理
import java.io.*;
public class Demo1
{
public static void main (String[] args)
{
FileWriter fw = null;
try
{
//如果文件不存在,则新建
fw = new FileWriter("D:\\android\\JAVA\\JavaTest\\IO\\Deo.txt");
fw.write("moguangxue");
fw.flush();
fw.write("xuege");
}
catch (IOException e)
{
System.out.println (e.toString());
}
finally
{
if (fw != null)
{
try
{
fw.close();
}
catch (IOException e)
{
System.out.println ("close:"+e.toString());
}
}
}
}
}
例3:读数据,然后存在数组里,读完1K再打印
import java.io.*;
public class Demo2
{
public static void main (String[] args)
{
FileReader fr = null;
try
{
fr = new FileReader("Demo.txt");
char[] buf = new char[1024];
int len = 0;
while ((len = fr.read(buf)) != -1)
{
System.out.println (new String(buf, 0, len));
}
}
catch (IOException e)
{
System.out.println (e.toString());
}
finally
{
if (fr != null)
{
try
{
fr.close();
}
catch (IOException e)
{
System.out.println (e.toString());
}
}
}
}
}
字符流的缓冲区:
为什么要缓冲区:提高对流的操作效率
原理:其实就是对数组进行封装
对应的对象:
BufferedWriter
特有方法:
newline():跨平台的换行符
BufferedReader
特有方法:
ReadLine():一次读一行,到行标记时,将行标之前的字符数据作为字符型返回。读到末尾时,返回null。
在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,因此在建立缓冲区对象时,要先有流对象存在。
其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储。为了提高操作数据的效率。
代码上的体现:
写入缓冲区对象。
//建立缓冲区对象必须把流对象作为参数传递给缓冲区的构造方法。
如:
BufferedWrite bufw = new BufferedWrite (new FileWriter(“Demo.txt”));
Bufw.write(“abcdefg”); //将数据写入缓冲区
Bufw.flush(); //对缓冲区的数据进行刷新,将数据刷到目的地中。
Bufw.close(); //关闭缓冲区,其实关闭的是被包装在内部的流对象。
//读取缓冲对象
BufferedReader bufr = new BufferedReader (new FileReader(“Demo.txt”));
String line = null;
//按照行的形式取出数据。取出的每一行数据不包含回车符。
while ((line = bufr.readLine()) != null)
{
System.out.println (line);
}
bufr.close();
例:通过缓冲区的形式,对文本文件进行拷贝
import java.io.*;
public class Demo3
{
public static void main (String[] args) throws IOException
{
BufferedReader bufr = new BufferedReader(new FileReader("Demo.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("mo.txt"));
String line = null;
while ((line = bufr.readLine()) != null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
}
关于readLine()方法:
其实缓冲区的该方法,用的还是与缓冲区关联的流对象的readr方法。只不过,每次读到一个字符,先不进行具体操作,先进行临时存储。当读到回车标志时,将临时容器中存储的数据一次性返回。
字节流:
抽象基类:InputStream, OutputStream
字节流可愿意操作任何数据
注意:字符流使用的数组是字符数组。
字节流使用的数组是字节数组
FileOutputStream fos = new FileOutputStream (“a.txt”);
fos.write(“abcdefg”); //直接将数据写入了目的地
fos.close (); //只关闭资源
FileIbputStream fis = new FileInputStream(“a.txt”);
//fis.available(); //获取关联的文件的字节数。
//如果文件体积不是很大。
//可以这样操作。
byte[] buf = new byte[fis.available()]; //创建一个刚刚好的缓冲区。
//但是这有一个弊端,就是文件过大,大小超出jvm的内容空间时,会内存溢出。
fis.read(buf);
System.out.println(new String(buf));
直至目前学习的流对象:
字符流:FileReader
FileWriter
BufferedReader
BufferedReader
字节流:
FileOutputStream
FileInputStream
BufferedInputStream
BufferedOutputStram
?:字节流的read()方法读取一个字节,为什么返回的不是byte类型,而是int 类型呢?
答:因为read方法读到末尾时返回的是-1;
而在所操作的数据中的很容易出现多个连续1的情况,而连续读到8个1,就是-1.导致读取会提前停止。
所以将读到的一个字节给提升为一个int类型的数值,但是只保留原字节,并在剩余的二进制位补0.
具体操作: byte &0xFF
对于write方法,可以一次写入一个字节,但接收的是一个 int 类型的数据。
之写入该int类型的数值的最低的一个字节(8位)。
简单来说:read方法对读到的数据进行提升。 Write对操作的数据进行转换。
转换流:
特点:
1、 是字节流和字符流之间的桥梁
2、 该流对象中可以对取到的字节数据进行指定编码表的编码转换。
什么时候使用?
1、 当字节和字符之间有转换动作时
2、 流操作的数据需要进行编码表的指定时
具体的对象体现
1、 InputStreamReader:字节到字符的桥梁
2、 OutputStreamWriter:字符到字节的桥梁
流操作的基本规律
1、 明确数据源和数据目的地,其实就是为了明确是输入流还是输出流
2、 明确操作的数据是否是纯文本数据,其实是为了确定是字节流还是字符流
数据源:键盘(System..in), 硬盘File开头的流对象,内存(数组)
数据汇(数据目的):控制台System.out, 硬盘File开头的流对象,内存(数组)
需求:
将键盘键入的数据存储到一个文件中。
数据源:System.in
既然是源,使用的就是输入流,可用的体系有InputStream,Reader。
因为键盘录入进来的一定是纯文本数据,所以可以使用专门操作字符数据的Reader。
发现System.in对应的流是字节读取流。所以要将其进行转换,将字节转成字符即可。
所以要使用Reader体系中:InputStreamReader
接下来,是否需要提高效率呢?如果需要,那么就加入字符流的缓冲区:BufferedReader
BufferedReader bur = new BufferedReader(new InputStreamReader(System.in));
数据汇:一个文件,硬盘。
既然是数据汇,那么一定是输出流,可以用的OutputStream,Writer。
往文件中存储的都是文本数据,那么可以使用字符流较为方便:Writer
因为操作的是一个文件。所以使用Writer中的FileWriter。
是否要提高效率呢?是,那就使用BufferedWriter.
BufferedWriter bufr = new BufferedWriter(new FileWriter("a.txt"));