我正在编写Spring Batch程序,它在每行读入包含固定长度数据的文件并将值写入数据库。问题是这个文件的编码是US-ASCII,但它有scandinavic字母,最终是##或其他一些奇怪的字符。斯堪的纳维奇字符编码为0x5B =Ä,0x5C =Ö,0x5D =Å。否则它是大写的US-ASCII文本。
在此文件中阅读的最佳方法是什么?我目前正在使用随弹簧批量提供的FlatFileItemReader。
答案 0 :(得分:2)
我遇到了类似的问题,其中文本应该被编码为ASCII但是使用了国际字符。我的解决方案是使用Windows-1252编码读取字节。
从Javadoc我看到FlatFileItemReader有一个setEncoding方法。请尝试以下方法:
reader.setEncoding("Windows-1252");
并查看它是否能提供更好的结果。
答案 1 :(得分:1)
我猜这个字符集是ISO646-SE / -FI(7位),如http://www.aivosto.com/vbtips/charsets-7bit.html中所述。 Java似乎并不支持开箱即用。您可以实现自定义Charset
。我不知道Spring,但是从JavaDoc来看,您可能必须在BufferedReaderFactory
上设置FlatFileItemReader
。
以下代码可能是一个起点:
public static void main(String[] args) {
try {
InputStream is = new ByteArrayInputStream(new byte[]{ 0x5B, 0x5C, 0x5D });
BufferedReader br = new BufferedReader(new InputStreamReader(is, new ISO646SECharset()));
// Spring: set custom BufferedReaderFactory returning BufferedReader like above line?
System.out.println(br.readLine());
br.close();
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
/** ISO646-SE/-FI 7-bit character set. */
public static class ISO646SECharset extends Charset {
private static final char[] b2c = new char[0x80];
private static final Map<Character, Byte> c2b = new HashMap<>(0x80);
static {
for (int i = 0; i < b2c.length; i++) { b2c[i] = (char) i; }
// see http://www.aivosto.com/vbtips/charsets-7bit.html
// see http://www.utf8-zeichentabelle.de/
b2c[0x24] = '\u00A4';
b2c[0x5B] = '\u00C4';
b2c[0x5C] = '\u00D6';
b2c[0x5D] = '\u00C5';
b2c[0x7B] = '\u00E4';
b2c[0x7C] = '\u00F6';
b2c[0x7D] = '\u00E5';
b2c[0x7E] = '\u00AF';
for (int i = 0; i < b2c.length; i++) { c2b.put(b2c[i], (byte) i); }
}
protected ISO646SECharset() {
super("ISO646-SE", new String[]{ "ISO646-FI" });
}
@Override
public boolean contains(Charset cs) {
return false;
}
@Override
public CharsetDecoder newDecoder() {
return new CharsetDecoder(ISO646SECharset.this, 1.0f, 1.0f) {
@Override
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
while (true) { // TODO optimize, see US_ASCII class of OpenJDK
if (in.remaining() <= 0) return CoderResult.UNDERFLOW;
if (out.remaining() <= 0) return CoderResult.OVERFLOW;
byte b = in.get();
if ((b & 0x80) != 0) b = (byte) '?';
out.put(b2c[b & 0x7F]);
}
}
};
}
@Override
public CharsetEncoder newEncoder() {
return new CharsetEncoder(ISO646SECharset.this, 1.0f, 1.0f) {
@Override
protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
while (true) {
if (in.remaining() <= 0) return CoderResult.UNDERFLOW;
if (out.remaining() <= 0) return CoderResult.OVERFLOW;
Byte b = c2b.get(in.get());
out.put(b != null ? b : (byte) '?');
}
}
};
}
}
修改:在How to define a new Charset in Java/Android?中,他们提到如何通过定义允许Charset
使用的CharsetProvider
来注册setEncoding('ISO646-SE')
。