Reader和Writer

本文介绍了Java中的字符流Reader和Writer,它们是输入输出流的抽象类,提供读写字符的功能。Reader用于从文件读取字符到控制台,Writer则用于将控制台内容写入文件。文章详细讲解了Reader和Writer的常用方法,如read、write、close等,并探讨了缓冲技术在Writer中的应用。同时,通过示例展示了如何使用Reader和Writer进行数据的读写操作。

Writer用于写出去到文件中,Reader用于把外面的文件读进控制台
Writer和Reader有很多子类,但是子类大多都是直接运用父类Writer和Reader的方法,而且Writer和Reader方法不多,且有共性,故只要搞懂Writer和Reader的方法即可。Writer和Reader都是抽象类,所以想输入输出只能用他们的子类。

字节流不能直接操作Unicode字符,所以java提供了字符流,汉字在文件中占用2个字节,如果使用字节流,读取不当会出现乱码现象,采用字符流就可以避免这个现象,在Unicode字符中,一个汉字被看作一个字符。
所有字符输入流类都是Reader(输入流)抽象类的子类,而所有字符输出流都是Writer(输出流)抽象类的子类。

Reader常用方法

读取方法
int read() 用于从流中读出一个字符,并将它返回
int read(char buffer[]):将从流中读出的字符放到字符数组buffer中,返回读出的字符数
int read(char buffer[],int offset,int length):将读出的字符放到字符数组的指定offset开始的空间,每次最多读出length个字符

其他方法:
void close():关闭Reader流
skip(long n):跳过指定的n个字符
boolean ready():判断流是否已经准备好被读取
void mark(int readAheadLimit)
void reset()

Reader例子

Reader fr = new FileReader("C:/mydata.txt");
BufferedReader br = new BufferedReader(fr);
String record = null;
int count = 0;
while ((record = br.readLine()) != null) {
    count++;
    System.out.printf(“%d:%s“,count,record);
}

Reader类
低级Reader类:
CharArrayReader
StringReader
PipedReader
FileReader
高级Reader类
BufferedReader
InputStreamReader
LineNumberReader

Writer工作原理

将写入的数据先存储到缓冲区,随着刷新而将缓冲区中的数据输入到文件中,刷新后缓冲区清空,这就是缓冲技术。因而有了BufferWriter,对BufferWriter操作实际是对与BufferedWriter关联的FileWriter类操作,所以对BufferedWriter进行flush和close实际上是对FileWriter进行flush和close。

Reader读进来只能一个一个字符去读,所以这里缓冲技术显得格外重要。

复制的原理:将文本中的数据缓存到Reader流中,再新建个文件,用Writer释放出去。

Writer常用方法

写入方法:
void write(int c):将参数c的低16位组成字符写入到流中。
void write(char[] buffer):将字符数组buffer中的字符写入到流中。
void write(char[] buffer, int offset, int length):将字符数组buffer中从offset开始的length个字符写入到流中。
void write(String string):将string字符串写入到流中。
void write(String string, int offset, int length):将字符string中从offset开始的length个字符写入到流中。
其他方法:
void close():和OutputStream的close方法类似。
void flush():和OutputStream的flush方法类似。

Writer例子

try {
//字符文件输出流
    Writer fw = new FileWriter(“c:/mydata.txt"); 
//打印流
PrintWriter out = new PrintWriter(fw); out.print("面朝大海,春暖花开!"); 
  out.printf(“%d * %d = %d“, 2, 3, 2*3); out.close();                                  
    fw.close();                                   
} catch (IOException e) {                             
    e.printStackTrace();                          
} 

从键盘输入数据,保存到文件中

//InputStreamReader为字节转换为字符输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new FileWriter(“d:\\abc.txt”));

String line = null;
while((line = reader.readLine()) != null){
    if(“quit”.equals(line.toLowerCase())){
        break;
    }
  pw.println(line);
}
pw.close();

Writer相关类
低级Writer类:
CharArrayWriter
StringWriter
PipedWriter
FileWriter
高级Writer类:
BufferedWriter
OutputStreamWriter
PrintWriter

用法示例:

//writer的用法
public class IOWriter {

    /**
     * @param IO流中的writer
     * 向demo.txt文本中写入东西
     * 如果是FileWriter fileWriter=new FileWriter("D:\\demo.txt",true);则是在之前的基础上续写
     * 如果没有true,则是覆盖之前写的所以内容
     */
    public static void main(String[] args) {

        try {
            FileWriter fileWriter=new FileWriter("D:\\demo.txt");
            fileWriter.write("abc");
            fileWriter.write("defg");
            fileWriter.flush();//flush刷新后,流可以继续使用
            fileWriter.close();//close刷新后,流关闭
        } catch (IOException e) {
            e.printStackTrace();
        }  
    }
}

//reader的用法

public class IOReader {
    /**
     * @param IO流中的Reader
     * 把demo.txt中的字符流都读出来 
     */
    public static void main(String[] args) {
        try {
            FileReader fileReader=new FileReader("D:\\demo.txt");    
            char[] buffer=new char[1024];
            int len=0;
            while((len=fileReader.read(buffer))!=-1) {
                System.out.println(new String(buffer, 0, len));
            }
//第一种方法:
            /*
               while(true) {    
                int a=fileReader.read();
                if(a==-1) {
                    break;
                }
                System.out.print((char)a+"");
            }*/

//第二种方法:
            /*int a=0;
            while ((a=fileReader.read())!=-1) {
                System.out.print((char)a+"\t");
            }*/

//第三种方法:     
            /*
             * 读取文件的方法(经典)
             */
            /*char[] buf=new char[1024];
            int len=0;
            while((len=fileReader.read(buf))!=-1) {
                String bufferString=new String(buf, 0, len);
                System.out.println(bufferString);
            }*/        
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

参考博客:
http://blog.csdn.net/noble510520/article/details/50083555

<think>好的,我需要解决用户关于Apache NiFi中ConvertRecord处理器ReaderWriter参数为空的问题。用户之前询问了如何设计一个NiFi流程来从数据库读取数据并转换为JSON输出到日志,现在遇到了ConvertRecord配置的问题。 首先,用户提到ReaderWriter参数为空,这可能意味着在ConvertRecord处理器的配置中,用户没有正确设置记录读取器写入器。根据之前的回答,用户需要为ConvertRecord配置ReaderWriter,比如使用AvroReader或CSVReader作为Reader,JsonRecordSetWriter作为Writer。但用户现在遇到参数为空的情况,可能是因为他们没有正确创建或配置这些服务。 接下来,我需要思考可能的原因。首先,用户可能没有在NiFi的Controller Services中创建相应的ReaderWriter服务。ConvertRecord处理器需要引用这些控制器服务,如果用户没有创建,下拉菜单就会是空的。另外,用户可能创建了服务,但没有启用它们,导致无法选择。或者,服务类型不兼容,例如用户可能创建了一个不支持的Reader类型,导致ConvertRecord无法识别。 然后,我需要考虑解决方案。首先,用户需要进入Controller Services界面,创建正确的ReaderWriter。例如,对于数据库查询结果,如果之前的处理器(如QueryDatabaseTable)输出的是Avro格式的数据,那么需要配置AvroReader。同样,JsonRecordSetWriter需要配置为JSON输出。创建这些服务后,确保它们处于启用状态,这样在ConvertRecord的下拉菜单中就可以看到并选择它们了。 另外,可能用户对NiFi的数据流格式不熟悉。例如,QueryDatabaseTable默认可能使用Avro格式输出,所以用户需要配置AvroReader来解析数据。然后,ConvertRecord将使用这个Reader读取数据,再通过JsonRecordSetWriter转换为JSON。如果用户错误地选择了其他格式的Reader,比如CSV,但数据不是CSV格式,这也会导致问题,但这里的问题更可能在于服务未被正确创建或启用。 还需要提醒用户检查Controller Services的状态。在NiFi中,新创建的控制器服务默认是禁用的,必须手动启用。如果用户创建了服务但没有启用,ConvertRecord就无法引用它们,导致参数为空。此外,服务可能存在配置错误,例如数据库连接信息错误,导致服务无法启用,这也需要检查。 另外,可能用户在使用ConvertRecord时,没有正确关联ReaderWriter的服务。例如,用户可能创建了AvroReader,但没有在ConvertRecord的Reader配置中选择它,或者创建了JsonRecordSetWriter但没有在Writer中选择。需要确保两个参数都正确选择了对应的控制器服务。 总结可能的原因:1)未创建所需的Reader/Writer控制器服务;2)服务未启用;3)服务类型不匹配;4)服务配置错误导致无法启用;5)在ConvertRecord中未正确选择已创建的服务。 在回答时,需要逐步引导用户检查这些可能性,并提供具体的配置步骤。例如,指导用户如何创建AvroReaderJsonRecordSetWriter,启用它们,并在ConvertRecord中选择这些服务。同时,给出示例配置,帮助用户理解每个步骤应该如何操作。此外,需要提醒用户注意数据格式的匹配,确保Reader能够正确解析上游处理器输出的数据格式。</think>当你在 Apache NiFi 的 `ConvertRecord` 处理器中遇到 **Reader Writer 参数为空**的情况时,通常是因为未正确配置相关的 **控制器服务(Controller Services)**。以下是详细原因解决方法: --- ### **为什么 Reader/Writer 参数为空?** 1. **未创建对应的控制器服务** `ConvertRecord` 的 Reader Writer 需要依赖独立的控制器服务(如 `AvroReader`、`JsonTreeWriter`),这些服务需先在 NiFi 的全局配置中创建并启用。 2. **控制器服务未启用** 即使创建了服务,如果未手动启用(状态为 `ENABLED`),也无法在下拉列表中看到。 3. **服务类型不匹配** 例如:Reader 必须与上游数据格式兼容(如 `QueryDatabaseTable` 默认输出 Avro 格式,需选择 `AvroReader`)。 --- ### **解决方法** #### **步骤 1:创建控制器服务** 1. **进入控制器服务配置界面** - 在 NiFi 画布空白处右键 → **Configure** → **Controller Services** → **+** 添加服务。 - **Reader 选择**(解析输入数据): - 若上游是 `QueryDatabaseTable`,选择 **`AvroReader`**(默认输出 Avro 格式)。 - 若上游是 CSV 数据,选择 **`CSVReader`**。 - 输出 JSON 时选择 **`JsonRecordSetWriter`** 或 **`JsonTreeWriter`**。 ![Controller Services 界面示例](https://nifi.apache.org/assets/images/controller-services-config.png) 2. **配置 Reader/Writer 服务** - 通常无需额外配置,保留默认值即可(除非需要自定义 Schema)。 - **以 `JsonRecordSetWriter` 为例**: - 设置 `Schema Write Strategy` 为 `Do Not Write Schema`(不嵌入 Schema)。 - 配置日期格式(如 `yyyy-MM-dd HH:mm:ss`)或字段顺序。 #### **步骤 2:启用控制器服务** - 在 **Controller Services** 界面,找到刚创建的服务,点击右侧的 **Enable** 按钮(⚡️图标)。 - **确保服务状态变为 `ENABLED`**(禁用状态的服务无法被引用)。 #### **步骤 3:关联服务到 ConvertRecord** 1. 双击 `ConvertRecord` 处理器 → **PROPERTIES** 标签。 2. 在 **Record Reader** **Record Writer** 的下拉菜单中,选择已启用的服务: ![ConvertRecord 配置示例](https://nifi.apache.org/assets/images/convert-record-config.png) --- ### **完整配置示例** ```plaintext # 流程链路 [QueryDatabaseTable] → [ConvertRecord] → [LogAttribute] # Controller Services 配置 - AvroReader (已启用) - JsonRecordSetWriter (已启用) # ConvertRecord 参数 - Record Reader = AvroReader - Record Writer = JsonRecordSetWriter ``` --- ### **常见错误排查** 1. **服务未启用** - 检查控制器服务的状态是否为 `ENABLED`(红色⚡️表示禁用)。 2. **Schema 不匹配** - 若上游数据字段与 JSON 映射失败,需在 `AvroReader` 中明确指定 Schema 文件或内联 Schema。 3. **依赖缺失** - 某些数据库驱动(如 MySQL JDBC)需手动将 JAR 文件放入 NiFi 的 `lib/` 目录。 --- ### **附加提示** - **快速调试**:在 `ConvertRecord` 前添加 `LogAttribute`,检查原始数据格式是否符合 Reader 的预期(如是否为 Avro)。 - **动态字段**:若需自定义 JSON 结构,可使用 `JsonTreeWriter` 并配置 `Schema Access Strategy` 为 `Inherit Record Schema`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值