IO流笔记一

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();
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值