IO流分类
流的定义:流是指一连串流动的字符,是以先进先出方式发送信息的通道。
按流向分:输出流:OutputStream和Writer为基类
输入流:InputStream和Reader为基类
按处理数据单元划分:字节流:字节输入流:InputStream基类
字节输出流:OutputStream基类
字符流:字符输入流:Reader基类
字节输出流:Writer基类
一、字符流(FileReader、FileWriter)
public class CopyTextTest{
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args){
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader("demo.txt" );
fw = new FileWriter("copytest_2.txt" );
//创建一个临时容器,用于缓存读取到的字符
char[] buf = new char[BUFFER_SIZE];
//定义一个变量记录读取到的字符数(其实就是往数组里装的字符个
数)
int len = 0;
while((len = fr.read(buf)) != -1){
fw.write(buf,0,len);
}} catch(Exception e){
throw new RuntimeException("读写失败!");
} finally{
if(fw != null){
try{
fw.close();
} catch(IOException e){
System.out.println(e.toString());
}}if(fr != null){
try{
fw.close();
} catch(IOException e){
System.out.println(e.toString());
}
}
}
}
字符流的缓冲区,缓冲区的出现提高了对数据的读写效率。
对应类:
BufferedWriter
BufferedReader
bufr.readLine():另外开辟了一个缓冲区,存储的是原缓冲区一行的数据,不包含换行符。
可以理解成对FileWriter和FileReader进行了装饰,即装饰模式
public class BufferedReaderDemo{
public static void main(String[] args) throws Exception{
FileReader fr = new FileReader("buf.txt" );
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line = bufr.readLine()) != null){
System.out.println(line);
}
bufr.close();
}
while((line = bufr.readLine()) != null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
public class LineNumberReaderDemo{
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("LineNumberReaderDemo.java" )
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(100);
while((line = lnr.readLine()) != null){
System.out.println(lnr.getLineNumber() + ":" + line);
}
lnr.close();
}
}
结果如下:
二、装饰设计模式
对原有类进行了功能的改变,增强
通过增强方法或者继承的方式
特点:装饰类和被装饰类都必须所属同一个接口或者父类。
缓冲区中无非就是封装了一个数组,并对外提供了更多的方法对数组进行访问,其实这些方法最终操
作的都是数组的角标
缓冲的原理:
其实就是从源中获取一批数据到缓冲区中,再从缓冲区中不断地取出一个一个数据。
在此次取完后,再从源中继续取一批数据进缓冲区,当源中的数据取完时,用-1作为结束标记。
class MyBufferedReader{
private Reader r;
//定义一个数组作为缓冲区
private char[] buf = new char[1024];
//定义一个指针用于操作这个数组中的元素,当操作到最后一个元素后,指针应该归
private int pos = 0;
//定义一个计数器用于记录缓冲区中的数据个数,当该数据减到0,就从源中继续获取数据到缓冲区中
private int count = 0;
MyBufferedReader(Reader r){
this .r = r;
}
//该方法从缓冲区中一次取一个字符
public int myRead() throws IOException {
//从源中获取一批数据到缓冲区中,需要先做判断,只有计数器为0时,才需要从源
中获取数据
if (count == 0){count = r.read(buf);
//每次获取数据到缓冲区后,角标归零
pos = 0;
}
if (count < 0)
return -1;
char ch = buf[pos];
pos++;
count--;
return ch;
}
}
三、字节流
基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。
public static void demo_write() throws IOException {
//1、创建字节输出流对象,用于操作文件
FileOutputStream fos = new FileOutputStream( "bytedemo.txt");
//2、写数据,直接写入到了目的地中
fos.write( "abcdefg".getBytes());
//关闭资源动作要完成
fos.close();
}
FileOutputStream
public static void demo_read2() throws IOException {
FileInputStream fis = new FileInputStream("bytedemo.txt" );
//建议使用这种读取数据的方式
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1){
System.out.println( new String(buf,0,len));
}
fis.close();
}
FileOutputStream、FileInputStream的flush方法内容为空,没有任何实现,调用没有意义
public static void copy_1() throws IOException {
FileInputStream fis = new FileInputStream("0.mp3" );
FileOutputStream fos = new FileOutputStream("1.mp3" );
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1){
fos.write(buf,0,len);
}
fis.close();
fos.close();
}
四、转换流
转换流的由来:
字符流与字节流之间的桥梁、方便了字符流与字节流之间的操作
InputStreamReader:字节到字符的桥梁,解码。
OutputStreamWriter:字符到字节的桥梁,编码
public static void main(String[] args) throws IOException {
//字节流
InputStream in = System.in;
//将字节转成字符的桥梁,转换流
InputStreamReader isr = new InputStreamReader(in);
//对字符流进行高效装饰,缓冲区
BufferedReader bufr = new BufferedReader(isr);
String line = null;
//读取到了字符串数据
while((line = bufr.readLine()) != null){
if("over" .equals(line))
break;
System.out.println(line.toUpperCase());
}
}
使用字节流读取一个中文字符需要读取两次,因为一个中文字符由两个字节组成,而使用字符流只需读取一次。
System.out的类型是PrintStream,属于OutputStream类别。OutputStreamReader是字符流通向字节流的桥梁。
示例:
public static void main(String[] args) throws IOException {
BufferedReader bufr = new BufferedReader(new
InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new
OutputStreamWriter(System.out));
String line = null;
while((line = bufr.readLine()) != null){
if("over" .equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
流的操作规律
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
3、明确具体的设备
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4、是否需要其他额外功能
是否需要高效ÿ缓冲区,是,就加上buffer
FileWriter
FileWriter是用来写入字符文件的便捷类,此类的构造方法假定默认字符编码和默认字节缓冲区大小都
是可接受的
任何Java识别的字符数据使用的都是Unicode码表,但是FileWriter写入本地文件使用的是本地编码,
也就是GBK码表。
而OutputStreamWriter可使用指定的编码将要写入流中的字符编码成字节
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"GBK");
UTF-8编码,一个中文三个字节。
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
readText();
}
public static void readText() throws IOException {
FileReader fr = new FileReader("d.txt" );
char[] buf = new char[10];
int len = fr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
fr.close();
}
}
原因分析:由于d.txt文件中是UTF-8编码的“您好”,6个字节。
使用FileReader类是用GBK编码进行读取,6个字节代表3个字符,并且按照GBK进行解码,因此才出
现如上结果。
什么时候使用转换流呢?
1、源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁,提高对文本
操作的便捷。
2、一旦操作文本涉及到具体的指定编码表时,必须使用转换流
File类
File类用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数
流只能操作数据,不能操作文件。
File.separator是与系统有关的默认名称分隔符。在 UNIX 系统上,此字段的值为 '/';在 Microsoft
Windows 系统上,它为 '\\
File对象的常用方法:
1、获取
获取文件名称
获取文件路径
获取文件大小
获取文件修改时间
系统根目录和容量获取
public static void listRootsDemo() throws IOException {
File[] files = File.listRoots();
for(File file : files){
System.out.println(file);
}
File file = new File("d:\\" );
System.out.println( "getFreeSpace:" + file.getFreeSpace());
System.out.println( "getTotalSpace:" + file.getTotalSpace());
System.out.println( "getUsableSpace:" + file.getUsableSpace());
}
获取c盘目录下的隐藏文件
public static void listDemo(){
File dir = new File("c:\\" );
File[] files = dir.listFiles( new FilterByHidden());
for(File file : files){
System.out.println(file);
}
}
class FilterByHidden implements FilenameFilter{
public boolean accept(File dir,String name){
return dir.isHidden();
}
}
Properties集合
特点:
1. 该集合中的键和值都是字符串类型。
2. 集合中的数据可以保存到流中,或者从流中获取。
3. 通常该集合用于操作以键值对形式存在的配置文件。
Properties集合的存和取
public static void propertiesDemo(){
//创建一个Properties集合
Properties prop = new Properties();
//存储元素
prop.setProperty( "zhangsan","10" );
prop.setProperty( "lisi","20" );
prop.setProperty( "wangwu","30" );
prop.setProperty( "zhaoliu","40" );
//修改元素
prop.setProperty( "wangwu","26" );
//取出所有元素
Set<String> names = prop.stringPropertyNames();
for(String name : names){
String value = prop.getProperty(name);
System.out.println(name + ":" + value);
}
}
Properties集合和流对象相结合的功能
public class PropertiesDemo{
public static void main(String[] args){
propertiesDemo();
}
public static void propertiesDemo(){
Properties prop = new Properties();
prop.setProperty( "zhangsan","10" );
prop.setProperty( "lisi","20" );
prop.setProperty( "wangwu","30" );
prop.setProperty( "zhaoliu","40" );
prop.list(System.out);
}
}
public static void propertiesDemo() throws Exception
Properties prop = new Properties();
prop.setProperty( "zhangsan","10" );
prop.setProperty( "lisi","20" );
prop.setProperty( "wangwu","30" );
prop.setProperty( "zhaoliu","40" );
//想要将这些集合中的字符串键值信息持久化存储到文件中
//需要关联输出流
FileOutputStream fos = new FileOutputStream("info.txt" );
//将集合中数据存储到文件中
prop.store(fos, "name+age");
fos.close();
}
public static void propertiesDemo() throws Exception
Properties prop = new Properties();
//集合中的数据来自于一个文件。
//注意:必须要保证该文件中的数据是键值对。
//需要使用到读取流
FileInputStream fis = new FileInputStream("info.txt" );
//使用load方法
prop.load(fis);
prop.list(System.out);
test();
myLoad();
}
//对已有的配置文件中的信息进行修改。
//读取这个文件。并将这个文件中的键值数据存储到集合中。再通过集合对数据进行修改//再通过流将修改 后的数据存储到文件中
public static void test() throws Exception {
//读取这个文件
File file = new File("info.txt" );
if(!file.exists()){
file.createNewFile();
}
FileReader fr = new FileReader("info.txt" );
//创建集合存储配置信息
Properties prop = new Properties();
//将流中信息存储到集合中
prop.load(fr);
prop.setProperty( "wangwu","26" );
FileWriter fw = new FileWriter(file);
prop.store(fw, "");
fr.close();
}