2013-11-27 90 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字節。