Jackcess:用于MSAccess数据库的错误字符集

我有一个MS-Access数据库,其中有“encryption”string。 这些看起来像这样: 加密字符串

但是,我很快注意到这些string的长度恰好与明文的长度(我知道明文)相匹配。 所以,用Excel试一下,我发现如果你使用=CODE(<char>)函数(所以你得到的字符代码在默认字符集,和=CHAR(<number>) viceversa)和用这个符号代表字母代码的这个数字代表你总会得到相同的结果。 这意味着我只需要用java和瞧这些值创build一个数组。 Excel示例(在右边提到的“数组”): excel示例解码 例如:“>>”具有(dec)187的索引,所以187x或253产生70 =>“F”

现在,我使用jackcess来访问这些值,“解密”大多是好的,但我有时从string中得到错误的字符。 在Excel中,一切正常。 具有最佳结果的代码:

 public static final int[] DECRYPT_KEY = { 253, 203, 204, 217, 226, 205, 128, 201, 222, 183, 58, 217, 230, 201, 183, 211, 158, 203, 167, 213, 35, 33, 201, 123, 186, 247 }; public static void main(String[] args) throws IOException { System.out.println(System.getProperty("file.encoding")); Database db = DatabaseBuilder.open(new File("/home/***/TM.db")); Table table = db.getTable("personal"); for (Row row : table) { String vorname = row.getString("vorname"); byte[] vornameArr = vorname.getBytes("cp1252"); for (int i1 = 0; i1 < vornameArr.length; i1++) { vornameArr[i1] = (byte) ((vornameArr[i1] & 0xff) ^ DECRYPT_KEY[i1]); } System.out.println(new String(vornameArr, "cp1252")); } } 

但正如我所说,一些字符仍然是错误的,但在Excel中,但一切都很好。 当我打印出getBytes("cp1272")给出的数字时,与Excel的完全不同。

你有什么想法,我可能做错了什么,为什么java给有时这样不同的值比Excel? 什么是更好的方法? 我已经尝试过所有的字符组合,有些在其他人失败的地方工作,但后来有其他错误的结果。

我可以用你的问题中的字节值来重新创build你的问题。 该线

 byte[] vornameArr = vorname.getBytes("cp1252"); 

尝试将vorname字符转换为cp1252字节,但没有对应于U + 008F(十进制143, SINGLE SHIFT THREE )的cp1252字符,因此Java会将该字符转换为问号(0x3F)。 因此,你的解码步骤是解码0x3F而不是0x8F,这就是为什么你得到“FadiÝa”,而不是“Fadima”。

通过replace上面的单行,我能够得到正确的结果

 byte[] doubleBytes = vorname.getBytes("UTF-16LE"); // 187 0 170 0 168 0 ... byte[] vornameArr = new byte[doubleBytes.length / 2]; for (int i = 0; i < vornameArr.length; i++) { vornameArr[i] = doubleBytes[i * 2]; // remove nulls } 

然后通过解码循环运行vornameArr字节。 (如果您愿意,也可以在上面的循环中应用解码转换。)

所以感谢@Gord Thompson和他build议的网站(fileformat.info)我终于find了一个答案:有时候字符看起来很相似,由于某种原因,在数据库中“较高”的字符是首选的(比如Unicode字符402和131) 。 我的java代码预计一切都有较低的价值,如Excel提供。 所以,如果代码高于255,则需要用较低的值代替。 出于某种原因, getBytes("cp1252")将始终返回较低的值,但toCharArray()getBytes("UTF-16LE")将返回更高的正确值(Compare: fileformat 192 )

所以我的代码现在是这样的,完美的工作:

 String vorname = row.getString("vorname"); char[] vornameArr = vorname.toCharArray(); for (int i = 0; i < vornameArr.length; i++) { if (vornameArr[i] > 255) { vornameArr[i] = (char) (String.valueOf(vornameArr[i]).getBytes("cp1252")[0] & 0xff); } vornameArr[i] = (char) (vornameArr[i] ^ DECRYPT_KEY[i]); } System.out.println(String.valueOf(vornameArr)); 

非常感谢您的帮助!