前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中的IO流(二)字符流的常用操作

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

作者头像
HcodeBlogger
发布2020-07-14 10:00:19
7890
发布2020-07-14 10:00:19
举报
文章被收录于专栏:Hcode网站Hcode网站

前言

今天带来的是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. 释放资源。
④流的关闭

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

代码语言:javascript
复制
流的对象的创建
try{
    流的操作
  }catch (IOException e) {
    异常处理
}finally{
    流的释放
}

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

代码语言:javascript
复制
try(流对象的创建){
    流的操作
  }catch (IOException e) {
    异常处理
}

字符流具体使用

Ⅰ文件流

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

①从文件中读取字符
代码语言:javascript
复制
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();
            }
        }
    }
}
②将字符写入文件
代码语言:javascript
复制
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) 写一个字符串的一部分。

代码语言:javascript
复制
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) 跳过流中指定的字符数。

代码语言:javascript
复制
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()获取数据。

代码语言:javascript
复制
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();
        }
    }
代码语言:javascript
复制
 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等,装饰流类不可以单独使用,必须配合实体流或装饰流进行使用。作用:可以一定限度加快读写速度。

输入流例子:

代码语言:javascript
复制
Reader  r = new FileReader(File对象或者文件Path);//当然实例化可以是别的流的对象。
BufferedReader br = new BufferedReader(r);

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

输出流例子:

代码语言:javascript
复制
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),将字符读入数组的某一部分。

代码语言:javascript
复制
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) 写入字符串的某一部分。

代码语言:javascript
复制
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();
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年4月10日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 基础概念
  • IO流分类导向图
  • 何为输入流和输出流?
  • 字符流的分类
    • ①节点流
      • ②处理流
        • ③流的使用一般步骤
          • ④流的关闭
          • 字符流具体使用
            • Ⅰ文件流
              • Ⅱ字符串流
                • Ⅲ字符数组流
                  • Ⅳ缓冲流
                    • Ⅴ转换流
                      • Ⅵ字符打印流
                      相关产品与服务
                      容器服务
                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档