2013-11-27 92 views
2

我正在编写一个Java(确定,Groovy,但这并不重要)迁移脚本,以将BLOB字段从Oracle10g数据库复制到另一个。数据由MS Access应用程序创建。这些文件似乎有不正确的编码,我猜测MS Access或ODBC驱动程序以某种方式操纵文件。在使用MS Access创建的Oracle10g数据库中访问BLOBS

使用查询SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';我发现源数据库具有字符集WE8MSWIN1252

源表的定义是:

CREATE TABLE CTR_DOCUMENTS (
    CTR_ID  NUMBER(11)   NOT NULL, 
    CTR_A_ID  NUMBER(11), 
    CTR_FILENAME VARCHAR2(260 Char) NOT NULL, 
    CTR_COMMENT VARCHAR2(255 Char), 
    CTR_DATE  DATE, 
    CTR_DATA  BLOB 
) 

我访问像斑点这样:

def blob = sourceDB.firstRow("SELECT CTR_DATA FROM CTR_DOCUMENTS WHERE CTR_ID = ?", 
    [id]).CTR_DATA 
def blobSize = blob.length() 
def blobStream = blob.getBinaryStream() 
byte[] byteArray = new byte[blobSize] 
blobStream.read(byteArray) 

我保存了一些斑点作为文件,以及编码看起来怪异和文件不能被他们的节目打开。第二个字节是始终00:

0000000: 2500 5000 4400 4600 2d00 3100 2e00 3500 %.P.D.F.-.1...5. 

我还观察到相同的行为与SQL客户端(SQL工作台/ J,的SQLDeveloper,TOAD)访问BLOBS。

对我来说,它看起来像我必须将文件从Windows-1252转换为UTF8,但这是行不通的。 我在这里错过了什么吗?

+4

BLOB是二进制文件,不应该有字符编码。表示文本的CLOB可以具有编码。 – GriffeyDog

+0

您可以为您的问题添加一个Oracle表定义吗? – ThinkJet

+0

正在将文件复制到另一个Oracle数据库?如果是,为什么不使用数据库链接?请参阅:http://stackoverflow.com/questions/6022706/is-there-a-way-to-copy-blob-records-between-databases-in-oracle-10g –

回答

2

从哪里开始,为了诊断的目的,如果没有别的办法,就是从输入BLOB的样本中扫描字节数组,以查看每个第二个字节实际上是否为0x00,并且每隔一个字节(非零)写入到bytesOut字节数组。如果成功,我会将bytesOut数组写入文件并查看它们是否现在是有效的PDF文档。例如:

public static void main(String[] args) { 
    try { 
     String connectionUrl = ""; 
     connectionUrl = 
       "jdbc:sqlserver://localhost;" + 
       "instanceName=SQLEXPRESS;" + 
       "databaseName=myDb;" + 
       "integratedSecurity=true"; 
     Connection con = DriverManager.getConnection(connectionUrl); 

     String SQL = 
       "SELECT CTR_ID, CTR_FILENAME, CTR_DATA " + 
       "FROM CTR_DOCUMENTS " + 
       "WHERE CTR_ID BETWEEN 1 AND 5"; 
     Statement stmt = con.createStatement(); 
     ResultSet rs = stmt.executeQuery(SQL); 

     while (rs.next()) { 
      boolean writeFile = true; 
      byte[] bytesIn = rs.getBytes("CTR_DATA"); 
      //scan input byte array and copy every second byte to output byte array 
      byte[] bytesOut = new byte[bytesIn.length/2]; 
      for (int i = 0; i < bytesIn.length; i++) { 
       if ((i % 2) == 1) { 
        if (bytesIn[i] != 0x00) { 
         System.out.println(String.format("Darn. bytesIn value at offset %d is not 0x00. Skipping...", i)); 
         writeFile = false; 
         break; 
        } 
       } 
       else { 
        bytesOut[i/2] = bytesIn[i]; 
       } 
      } 
      if (writeFile) { 
       String outFile = 
         "C:\\__tmp\\pdfTest\\" + rs.getString("CTR_FILENAME"); 
       FileOutputStream fos = new FileOutputStream(outFile); 
       fos.write(bytesOut); 
       fos.close(); 
       System.out.println(String.format("\"%s\" created.", outFile)); 
      } 
     } 
     rs.close(); 
     con.close(); 
    } catch(Exception e) { 
     System.out.println(e.getMessage()); 
     System.exit(0); 
    } 
} 

的理由是,如果沿途的某个地方,某个进程采取了什么它认为是一个单字节字符“字符串”(例如,Windows的1252),并转换为Unicode(例如,UCS-2LE),只需在每个字符后面插入0x00(而不用另外改变实际的数据字节),那么最直接的解决方案就是再次取出这些0x00字节。