我正在读取 Shift-JIS 编码的 XML 文件并将其存储在 ByteBuffer 中,然后将其转换为字符串,并尝试通过 Pattern 和 Matcher 查找字符串的开头和结尾。我尝试从这两个位置将缓冲区写入文件。当没有多字节字符时它可以工作。如果有一个多字节字符,我会错过末尾的一些文本,因为 end 的值有点偏离
static final Pattern startPattern = Pattern.compile("<\\?xml ");
static final Pattern endPattern = Pattern.compile("</doc>\n");
public static void main(String[] args) throws Exception {
File f = new File("20121114000606JA.xml");
FileInputStream fis = new FileInputStream(f);
FileChannel fci = fis.getChannel();
ByteBuffer data_buffer = ByteBuffer.allocate(65536);
while (true) {
int read = fci.read(data_buffer);
if (read == -1)
break;
}
ByteBuffer cbytes = data_buffer.duplicate();
cbytes.flip();
Charset data_charset = Charset.forName("UTF-8");
String request = data_charset.decode(cbytes).toString();
Matcher start = startPattern.matcher(request);
if (start.find()) {
Matcher end = endPattern.matcher(request);
if (end.find()) {
int i0 = start.start();
int i1 = end.end();
String str = request.substring(i0, i1);
String filename = "test.xml";
FileChannel fc = new FileOutputStream(new File(filename), false).getChannel();
data_buffer.position(i0);
data_buffer.limit(i1 - i0);
long offset = fc.position();
long sz = fc.write(data_buffer);
fc.close();
}
}
System.out.println("OK");
}
最佳答案
使用字符串索引 i0 和 i1 来表示字节位置:
data_buffer.position(i0);
data_buffer.limit(i1 - i0);
是错误的。由于 UTF-8 没有给出唯一的编码,ĉ
被写成两个字符 c
+ 组合变音标记 ^
,之间来回翻译字符和字节不仅昂贵而且容易出错(在特定数据的 rand 情况下)。
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
new File(filename)), "UTF-8"));
或者使用 CharBuffer,它实现了 CharSequence。
<小时/>而不是写入 FileChannel fc:
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
new File(filename)), "UTF-8"));
try {
out.write(str);
} finally {
out.close();
}
CharBuffer 版本需要更多重写,还涉及模式匹配。
关于java - 多字节字符 - 模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13400370/