Oracle/PLSQL读取dat文件时能否识别换行符CHR(10)或CHR(13)?
在Oracle中校验dat文件行尾换行符的实现方案
需求与问题
需要校验dat文件的每行格式:
- 每行必须以
CHR(10)(换行符LF)结尾,不能是CHR(13)(回车符CR)或其他字符 - 每行的第160位必须是
CHR(10),不符合则抛出错误
但使用UTL_FILE.GETLINE读取文件时,该函数会自动截断行尾的换行符(CR/LF/CRLF组合都会被剔除),导致无法直接获取并校验这些字符,因此需要确认Oracle中是否能实现该校验逻辑。
实现方案
可以实现。UTL_FILE.GETLINE的特性就是自动移除行尾换行符,所以要获取原始文件字节(包括换行符),需要改用二进制读取模式,通过UTL_FILE.GET_RAW逐块读取原始字节数据,再对字节进行校验。
示例代码
SET SERVEROUTPUT ON; DECLARE v_file UTL_FILE.FILE_TYPE; v_raw_data RAW(4000); v_byte NUMBER; v_line_pos NUMBER := 0; v_line_len CONSTANT NUMBER := 160; -- 每行固定160字节 BEGIN -- 以二进制只读模式打开文件,避免字符集转换干扰原始字节 v_file := UTL_FILE.FOPEN('DIR_IN_IMP_ACT_VENTE', 'temp.dat', 'RB'); LOOP BEGIN -- 每次读取160字节(对应一行的要求长度) UTL_FILE.GET_RAW(v_file, v_raw_data, v_line_len); v_line_pos := v_line_pos + 1; -- 检查第160位字节是否为CHR(10)(ASCII值为10) v_byte := UTL_RAW.SUBSTR(v_raw_data, v_line_len, 1); IF v_byte != 10 THEN RAISE_APPLICATION_ERROR(-20001, '第' || v_line_pos || '行不符合要求:第160位不是CHR(10)'); END IF; -- 检查整行是否包含CHR(13)(ASCII值为13) IF UTL_RAW.INSTR(v_raw_data, UTL_RAW.CAST_FROM_NUMBER(13)) > 0 THEN RAISE_APPLICATION_ERROR(-20002, '第' || v_line_pos || '行不符合要求:包含CHR(13)'); END IF; DBMS_OUTPUT.PUT_LINE('第' || v_line_pos || '行校验通过'); EXCEPTION WHEN NO_DATA_FOUND THEN -- 校验最后一行长度是否符合要求 IF v_line_pos = 0 OR UTL_RAW.LENGTH(v_raw_data) != v_line_len THEN RAISE_APPLICATION_ERROR(-20003, '最后一行长度不符合要求(需160字节)'); END IF; EXIT; END; END LOOP; UTL_FILE.FCLOSE(v_file); EXCEPTION WHEN OTHERS THEN IF UTL_FILE.IS_OPEN(v_file) THEN UTL_FILE.FCLOSE(v_file); END IF; RAISE; END; /
代码关键点说明
'RB'模式打开文件:二进制只读模式,确保读取的是文件原始字节,不会被Oracle字符集转换处理UTL_FILE.GET_RAW:直接读取原始字节数据,完整保留所有字符(包括CR/LF)UTL_RAW.SUBSTR/UTL_RAW.INSTR:专门用于操作RAW类型的字节数据,精准校验目标字节位置和内容- 自定义异常:不符合条件时抛出明确错误信息,便于定位问题
原测试代码的问题
你原代码中使用的UTL_FILE.GETLINE会自动截断行尾的CHR(10)、CHR(13)或CHR(13)||CHR(10)组合,导致V1变量中不会包含这些换行符,因此无法通过SUBSTR(V1, -1)获取到行尾的换行符,这是无法完成校验的核心原因。
内容的提问来源于stack exchange,提问作者Ayushi Ramsurn
相关产品推荐
相关产品推荐

