专栏首页Hcode网站Java中的IO流(二)字符流的常用操作

Java中的IO流(二)字符流的常用操作

前言

今天带来的是JAVA的IO流中的字符流,Reader和Writer子类流的用法。

基础概念

流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出。

IO流分类导向图

何为输入流和输出流?

其实输入(InputStream,Reader)和输出(OutputStream,Writer)是相对于程序来讲,例如一个文件的数据要想在程序中被操作,那么就得输入到程序,这就是输入,操作完成之后又想保存到文件里面,从程序输出数据到文件的过程就是输出。

字符流的分类

Reader 和 Writer 要解决的最主要问题是国际化。原先的 I/O 类库只支持8位的字节流,因此不能很好的处理16位的Unicode字符。Unicode 是国际化的字符集,这样增加了Reader 和 Writer之后,就可以自动在本地字符集和Unicode国际化字符集之间进行转换。

①节点流

概念:可以从或向一个特定的地方(节点)读写数据。 1. 文 件 FileReader,FileWriter 文件进行处理的节点流。 2. 字符串 StringReader , StringWriter 对字符串进行处理的节点流 3. 数组 CharArrayReader和CharArrayWriter与ByteArrayInputStream和ByteArrayOutputStream 对应,从字符数组中读取数据。

②处理流

概念:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接

  1. 缓冲流(装饰流,装饰模式的其中之一): BufferedReader, BufferedWriter---增加缓冲功能,避免频繁读写硬盘。
  2. 转换流:InputStreamReader, OutputStreamReader实现字节流和字符流之间的转换。
  3. 字符打印流:PrintWriter 是字符类型的打印输出流,它继承于Writer,实现在PrintStream中的所有 与PrintStream类不同。

③流的使用一般步骤

  1. 选择源,即是选择要操作的文件或者数据。
  2. 选择流,想要实现何种流的操作。
  3. 流的操作。
  4. 释放资源。

④流的关闭

遵循先开后闭的原则,有多种流的使用时,最先创建的流对象最后关闭。(字节数组流可以不用关闭)

流的对象的创建
try{
    流的操作
  }catch (IOException e) {
    异常处理
}finally{
    流的释放
}

Java7提供了try-with-resources机制,其类似Python中的with语句,将实现了 java.lang.AutoCloseable 接口的资源定义在 try 后面的小括号中,不管 try 块是正常结束还是异常结束,这个资源都会被自动关闭。 try 小括号里面的部分称为 try-with-resources 块。

try(流对象的创建){
    流的操作
  }catch (IOException e) {
    异常处理
}

字符流具体使用

Ⅰ文件流

与FileInputStream和FileOutputStream对应,从文件系统中读取和写出字符序列。

①从文件中读取字符
public class IOTest {

    public static void main(String[] args) {
        //1、创建源
        File src = new File("123.txt");
        //2、选择流
        Reader  reader =null;
        try {
            reader =new FileReader(src);
            //3、操作 (分段读取)
            char[] flush = new char[1024]; //缓冲容器
            int len = -1; //接收长度
            while((len=reader.read(flush))!=-1) {
                //字符数组-->字符串
                String str = new String(flush,0,len);
                System.out.println(str);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //4、释放资源
            try {
                if(null!=reader) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
②将字符写入文件
public class IOTest {

    public static void main(String[] args) {
        //1、创建源
        File dest = new File("123.txt");
        //2、选择流
        Writer writer =null;
        try {
            writer = new FileWriter(dest);
            //3、操作(写出)
            //写法一
            String msg1 ="Himit_ZH真的帅\n\r";
            char[] datas =msg1.toCharArray(); // 字符串-->字符数组
            writer.write(datas,0,datas.length);
            writer.flush();
            //写法二
            String msg2 ="Himit_ZH真的帅\n\r";
            writer.write(msg2);
            writer.write("add");
            writer.flush();

            //写法三
            writer.append("Himit_ZH真的帅\n\r").append("我也这样认为!");
            writer.flush();
        }catch(FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            //4、释放资源
            try {
.               if (null != writer) {
                    writer.close();
                } 
            } catch (Exception e) {
            }
        }
    }
}

Ⅱ字符串流

String作为数据源 StringReader 是读, 从一个String中读取,所以需要一个String ,通过构造方法传递 StringWriter是写, 写入到一个String中去,所以它内部提供了一个StringBuffer中用来保存数据

StringWriter的API文档

构造器: StringWriter() 使用默认的初始字符串缓冲区大小创建新的字符串编写器。 StringWriter (int initialSize) 使用指定的初始字符串缓冲区大小创建新的字符串writer。 API的方法: StringWriter append​(char c) 将指定的字符追加到此writer。 StringWriter append​(CharSequence csq) 将指定的字符序列追加到此writer。 StringWriter append​(CharSequence csq, int start, int end) 将指定字符序列的子序列追加到此writer。 void close() 关闭 StringWriter无效。 void flush() 冲洗流。 StringBuffer getBuffer() 返回字符串缓冲区本身。 String toString() 将缓冲区的当前值作为字符串返回。 void write​(char[] cbuf, int off, int len) 写一个字符数组的一部分。 void write​(int c) 写一个字符。 void write​(String str) 写一个字符串。 void write​(String str, int off, int len) 写一个字符串的一部分。

public class IOtest {
    public static void main(String[] args) {
        char[] x = { 'a', 'b' };
        StringWriter s = new StringWriter(20); 
        s.write(x, 0, 1);
        s.write('a');
        s.write("bcd");
        s.write("012", 1, 2);
        s.append('a').append('b');
        s.flush();
        System.out.println(s.toString());
    }
}

StringReader的API文档

构造器 StringReader​(String s) 创建一个新的字符串阅读器。 API文档的方法: void close() 关闭流并释放与其关联的所有系统资源。 void mark​(int readAheadLimit) 标记流中的当前位置。 boolean markSupported() 判断此流是否支持mark()操作。 int read() 读一个字符。 int read​(char[] cbuf, int off, int len) 将字符读入数组的一部分。 boolean ready() 判断此流是否可以读取。 void reset() 将流重置为最新标记,如果从未标记过,则将其重置为字符串的开头。 long skip​(long ns) 跳过流中指定的字符数。

StringReader sr=new StringReader("himitzh");
System.out.println((char)sr.read());  // 读取a
// 如果支持标记读取,则标记当前的读取位置,也就是字符串中的第二个字符b
if(sr.markSupported()){
    sr.mark(3);          
}
System.out.println((char)sr.read());  // 读取i
System.out.println((char)sr.read());  // 读取m
sr.reset();                           // 从做标记的mark开始读取
System.out.println((char)sr.read());  // 当前读取位置设置为mark标记的值,输出为m

char[] x=new char[3];
sr.read(x,0,2);
System.out.println(String.valueOf(x));// 输出im

Ⅲ字符数组流

CharArrayReader实现一个可用作字符输入流的字符缓冲区。支持mark/set。 CharArrayWriter实现一个可用作字符输出流的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray()和 toString()获取数据。

public void IOtest() {
        char[] c = new char[] { 'h', 'i', 'm', 'i', 't', 'z', 'h' };
        try {
            CharArrayReader r = new CharArrayReader(c);

            // 从r中连续读取三个字节
            for (int i = 0; i < 3; i++) {
                if (r.ready() == true) {
                    char tmp = (char) r.read();
                    System.out.print(tmp);
                }
            }
            System.out.println("---------------------------");

            // 测试是否支持mark
            if (!r.markSupported()) {
                System.out.println("make not supported!");
                return;
            } else
                System.out.println("make supported!");

            // 标记,当前位置为i
            r.mark(0);

            // 跳过2个字符,当前位置为z
            r.skip(2);

            // 向下读取两个字符,zh
            char[] buf = new char[2];
            r.read(buf, 0, 2);
            System.out.println("buf:" + String.valueOf(buf));
            // 重置当前位置为上一次标记的位置,即为d
            r.reset();

            // 向下读取两个字符,it
            r.read(buf, 0, 2);
            System.out.println("buf:" + String.valueOf(buf));

            r.close();
            r.read();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 public void IOtest() {
     try {
          CharArrayWriter w = new CharArrayWriter();// 创建CharArrayWriter字符流,默认大小为32
           w.write('A');
           w.write("BCDEF");
           char[] charArr = new char[] {'a','b','c','d'};
           w.write(charArr, 1, 3);

           w.append('0').append("12345").append(String.valueOf(charArr), 3, 6);

           char[] buf = w.toCharArray();//将w转化为字符数组


            CharArrayWriter w2 = new CharArrayWriter(100);//指定最大为100字符
            w.writeTo(w2);//将w缓冲区内容写入到w2中

            w.reset();//重置,清空
            w2.close();   
            } catch (IOException e) {
                e.printStackTrace();
       }
}

Ⅳ缓冲流

装饰流指不直接连接数据源,而是以其它流对象(实体流对象或装饰流对象)为基础建立的流类,该类流实现了将实体流中的数据进行转换,增强流对象的读写能力,比较常用的有BufferedInputStream/BufferedOutputStream和BufferedReader/BufferedWriter等,装饰流类不可以单独使用,必须配合实体流或装饰流进行使用。作用:可以一定限度加快读写速度。

输入流例子:

Reader  r = new FileReader(File对象或者文件Path);//当然实例化可以是别的流的对象。
BufferedReader br = new BufferedReader(r);

-----------------------------------------------------------------
//装饰模式的写法 ~~俄罗斯套娃?~~ 
BufferedReader br = new BufferedReader(FileReader(File对象或者文件Path));

输出流例子:

Writer w = new FileWriter(File对象或者文件Path);//当然实例化可以是别的流的对象。
BufferedWriter bw = new BufferedWriter(w);
-----------------------------------------------------------------
//装饰模式的写法 ~~俄罗斯套娃?~~ 
BufferedWriter bw = new BufferedWriter(FileWriter(File对象或者文件Path));

Ⅴ转换流

作用:实现字节流和字符流之间的转换。 1、OutputStreamWriter,将字节输出流转换为字符输出流。

API方法: 1、flush():刷新该流的缓冲. 2、close():关闭此流,关闭前需要刷新 3、getEncoding():获取此流使用的字符编码的名称。 4、write():write(char[] ,int offset,int length),写入字符数组的某一部分 5、 write(String ,int offset ,int length),写入字符串的某一部分 write(String ),写入单个字符。

2、InputStreamReader,将字节输入流转换为字符输入流。

API方法: 1、close():关闭此流 2、getEncoding():获取此流使用的字符编码的名称 3、ready():判断此流是否已经准备好用于读取 4、read():read(),读取单个字符。 read(char[],int offset ,int length),将字符读入数组的某一部分。

public class ConvertTest {
    public static void main(String[] args) {
        //操作System.in 和System.out
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer =new BufferedWriter(new OutputStreamWriter(System.out));){
            //循环获取键盘的输入(exit退出),输出此内容
            String msg ="";
            while(!msg.equals("exit")) {
                msg = reader.readLine(); //循环读取
                writer.write(msg); //循环写出
                writer.newLine();
                writer.flush(); //强制刷新
            }
        }catch(IOException e) {
            System.out.println("操作异常");
        }
    }
}

Ⅵ字符打印流

PrintWriter 是字符类型的打印输出流,它继承于Writer,实现在PrintStream中的所有 与PrintStream类不同,如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。这些方法使用平台自有的行分隔符概念,而不是换行符。 此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常。

PrintWriterAPI文档

构造器: PrintWriter​(File file) 使用指定的文件创建一个没有自动行刷新的新PrintWriter。 PrintWriter​(File file, String csn) 使用指定的文件和字符集创建一个没有自动行刷新的新PrintWriter。 PrintWriter​(File file, Charset charset) 使用指定的文件和字符集创建一个没有自动行刷新的PrintWriter。 PrintWriter​(OutputStream out) 从现有的OutputStream创建一个没有自动行刷新的新PrintWriter。 PrintWriter​(OutputStream out, boolean autoFlush) 从现有的OutputStream创建一个新的PrintWriter。 PrintWriter​(OutputStream out, boolean autoFlush, Charset charset) 从现有的OutputStream创建一个新的PrintWriter。 PrintWriter​(Writer out) 创建一个新的PrintWriter,没有自动行刷新。 PrintWriter​(Writer out, boolean autoFlush) 创建一个新的PrintWriter。 PrintWriter​(String fileName) 使用指定的文件名创建一个没有自动行刷新的新PrintWriter。 PrintWriter​(String fileName, String csn) 使用指定的文件名和字符集创建一个没有自动行刷新的新PrintWriter。 PrintWriter​(String fileName, Charset charset) 使用指定的文件名和字符集创建一个没有自动行刷新的新PrintWriter。 使用方法: append(char c) 将指定字符添加到此 writer。 append(CharSequence csq) 将指定的字符序列添加到此 writer。 append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer。 boolean checkError() 如果流没有关闭,则刷新流且检查其错误状态。 void clearError() 清除此流的错误状态。 void close() 关闭该流并释放与之关联的所有系统资源。 void flush() 刷新该流的缓冲。 format(Locale l, String format, Object... args) 使用指定格式字符串和参数将一个格式化字符串写入此 writer 中。 format(String format, Object... args) 使用指定格式字符串和参数将一个格式化字符串写入此 writer 中。 void print() 参数可为基本数据类型,字符串,对象等。 void println() 多了个换行。 printf(Locale l, String format, Object... args) 使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。 printf(String format, Object... args) 使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。 void setError() 指示已发生错误。 void write(char[] buf) 写入字符数组。 void write(char[] buf, int off, int len) 写入字符数组的某一部分。 void write(int c) 写入单个字符。 void write(String s) 写入字符串。 void write(String s, int off, int len) 写入字符串的某一部分。

public static void main(String[] args) throws IOException {        
    //创建一个字符打印流对象
    PrintWriter pw = new PrintWriter(new FileWriter("123.txt")) ;
    PrintWriter pw = new PrintWriter(new FileWriter("123.txt"), true) ; //启动自动刷新    
    //写数据
    pw.print(111);
    pw.print("Himit_ZH");
    pw.print("你好");
    pw.print('a');
    char [] c = new char[]{'a','b','c'};
    pw.write(c)
    pw.write(c,1,3);//"bc"
    String str="sssss";
    pw.write(str);
    pw.println("hello");//本身自动换行并且向pw.txt文件打印内容        
    pw.flush(); //本身在构造的时候,就可以启动自动刷新        
    //关闭流
    pw.close();
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java中的IO流(一)字节流的常用操作

    今天带来的是JAVA的IO流中的字节流,InputStream和OutputStram子类流的用法。

    HcodeBlogger
  • Java利用多线程和Socket制作GUI界面的在线聊天室

    最近刚好是期末,碰上Java实训,借此将之前写的在线聊天室搬出来,加上GUI(Swing),当成实训作品,记录一下这次实训的结果。

    HcodeBlogger
  • Java中的IO流(三)Apache Commons IO组件的常用操作

    这次带来的是Apache开源组织的CommonsIO集成组件的FileUtils和IOUtils常用操作。

    HcodeBlogger
  • 搜罗的面试题总结(一)

    sizeof()作用:是C/C++的一个操作符,返回一个对象或类型所占内存字节数。

    用户5908113
  • ofbiz实体引擎(七) 检查数据源

    /** * Check the datasource to make sure the entity definitions are correct,...

    cfs
  • 浏览器中的跨域问题与 CORS

    跨域,这或许是前端面试中最常碰到的问题了,大概因为跨域问题是浏览器环境中的特有问题,而且随处可见,如同蚊子不仅盯你肉而且处处围着你转让你心烦。「你看,在服务器发...

    夜尽天明
  • 浏览器中的跨域问题与 CORS

    跨域,这或许是前端面试中最常碰到的问题了,大概因为跨域问题是浏览器环境中的特有问题,而且随处可见,如同蚊子不仅盯你肉而且处处围着你转让你心烦。「你看,在服务器发...

    山月
  • 字符串操作——C语言实现

    用户4645519
  • [十二]基础数据类型之String

    而对于字符的序列,也就是多个char, 这么一种东西, 使用CharSequence这个接口来描述

    noteless
  • Java编程最差实践(常见编程错误典范)

    转载自  http://macrochen.iteye.com/blog/1393502

    庞小明

扫码关注云+社区

领取腾讯云代金券