簡體   English   中英

在 JAVA 中將文件或 byte[] 轉換為 BLOB

[英]convert file or byte[] into BLOB in JAVA

我正在將一個文件從客戶端發送到服務器並像這樣接收它:

            //Receive File:
            FileOutputStream fis = new FileOutputStream("receivedTest");
            DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
            int count;
            byte[] buffer = new byte[4096];
            while ((count = dis.read(buffer)) > 0)
            {
              fis.write(buffer, 0, count);
            }
            fis.close();

就像本主題中所解釋的那樣。 它運作良好。 但事實是,我真的不想接收文件本身; 我想要一個 BLOB。 我讀過 BLOB 就像一個 byte[]。

在我的數據庫 class(我使用 SQLite)中,我有下表:

    String sqlFile = "CREATE TABLE IF NOT EXISTS files (\n"
            + " id integer PRIMARY KEY,\n"
            + " shorthash byte[],\n"
            + " filename text NOT NULL,\n"
            + " file blob,\n"
            + " owner text\n"
            + ");";

和以下 function 插入一個新的“文件”:

public void insertFile(byte[] shorthash, String filename, byte[] file, String owner) {
    String sql = "INSERT INTO files(shorthash,filename, file, owner) VALUES(?,?,?,?)";

    try (Connection conn = DriverManager.getConnection(url);
            PreparedStatement pstmt = conn.prepareStatement(sql)) {
        pstmt.setBytes(1, shorthash);
        pstmt.setString(2, filename);
        pstmt.setBytes(3, file);
        pstmt.setString(4, owner);
        pstmt.executeUpdate();
    } catch (SQLException e) {
        System.out.println(e.getMessage());
    }
}

如您所見,有 4 列,文件本身位於第 3 列。 在表中它被聲明為 BLOB,但是當我插入它時我只是在做一個 setBytes。 我不確定這是否正確,這正是我在 inte.net 上找到的。

所以,我在我的服務器上收到這個文件,我想把它存儲在我的數據庫中。 如果可能的話,我想避免在服務器端創建文件(行 FileOutputStream fis = new FileOutputStream("receivedTest"); 在我的第一個代碼中)。 我想將它直接存儲在數據庫中,因為我將它作為字節數組接收,我認為這樣會更容易。

但我不知道該怎么做。 可能是因為我不太了解 Blob 和 byte[] 之間的聯系。 我的意思是,字節數組可能太小而無法容納整個文件; 但是一滴沒關系。 但是,為了將文件插入數據庫,我插入了一個字節數組。 這讓我胡說八道。

編輯:

所以,我嘗試了兩件事:首先,將文件添加到數據庫中,就像它在此處所做的那樣(而且幾乎所有我看過的地方,它總是這樣做的):

//Receive encrypted File:
            FileOutputStream fos = new FileOutputStream("receivedTest");
            DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
            int count;
            byte[] buffer = new byte[4096];
            while ((count = dis.read(buffer)) > 0)
            {
              fos.write(buffer, 0, count);
            }
            fos.close();

            DB.insertFile(shorthash, "test", "receivedTest", user);

//Insert file in DB:
public void insertFile(byte[] shorthash, String filename, String filepath, String owner) throws FileNotFoundException {
    String sql = "INSERT INTO files(shorthash, filename, file, owner) VALUES(?, ?, ?, ?)";
    try (Connection conn = DriverManager.getConnection(url);
            PreparedStatement pstmt = conn.prepareStatement(sql)) {
        pstmt.setBytes(1, shorthash);
        pstmt.setString(2, filename);

        File file = new File(filepath);
        FileInputStream   fis = new FileInputStream(file);
        pstmt.setBinaryStream(3, fis, (int) file.length());
        pstmt.execute();
        pstmt.setString(4, owner);
        pstmt.executeUpdate();
        fis.close()
    } catch (SQLException e) {
        System.out.println(e.getMessage());
    }
}

其次,將文件作為字節數組插入(但這不適用於大文件),如SQLite 教程中所述:

//Insert file in DB:
public void insertFile(byte[] shorthash, String filename, String filepath, String owner) throws FileNotFoundException {
    String sql = "INSERT INTO files(shorthash, filename, file, owner) VALUES(?, ?, ?, ?)";
    try (Connection conn = DriverManager.getConnection(url);
            PreparedStatement pstmt = conn.prepareStatement(sql)) {
        pstmt.setBytes(1, shorthash);
        pstmt.setString(2, filename);

        File file = new File(filepath);
        FileInputStream   fis = new FileInputStream(file);    
        byte[] buffer = new byte[1024];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        for (int len; (len = fis.read(buffer)) != -1;)
            bos.write(buffer, 0, len);
        fis.close()
        pstmt.setBytes(3, bos.toByteArray());
        pstmt.execute();
        pstmt.setString(4, owner);
        pstmt.executeUpdate();
    } catch (SQLException e) {
        System.out.println(e.getMessage());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

然后,當我打印我的數據庫時,里面沒有文件。 如果我嘗試使用數據庫瀏覽器打開數據庫,也是如此。 控制台只說:

Connection to SQLite has been established. 
ouverture du server
Clients:

1   admin   admin

Files:

byte[]和BLOB只是討論任意一組二進制數據的兩種不同方式。 在Java中, byte[]是二進制數據的集合。 在數據庫中,BLOB代表Binary Large Object,並且是同一件事。 只是二進制數據的集合。

因此,根據參考框架的不同,它們是同一事物。 因此,當將byte[]存儲在blob列中時,您只是將這些字節從Java推送到數據庫中。 然后,當您讀回它們時,如果需要,可以將它們變成一個對象,因為數據庫沒有更改它們。 它只是直接存儲二進制信息。

您會發現,如果您是從其他地方編寫的Blob,則除非您知道所存儲二進制數據的編碼和字節序,否則可能無法將其轉換為對象。

如果您的文件太大而無法存儲在單個byte[]或者您想優化使用內存進行存儲的方式,則可以使用Stream將數據發送到db,而無需將所有數據都保留在同一內存中時間。

最后,如果需要將FileInputStream轉換為字節,則可以使用Apache Commons IO,如下所示:

byte[] bytes = IOUtils.toByteArray(fis);

然后存儲您的文件。

將文件作為十六進制字符串插入

public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for ( int j = 0; j < bytes.length; j++ ) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

String strFilte = "x" + "’" + bytesToHex(file) + "’"

pstmt.setString(3, strFile);

我設法找到了一種方法。 它仍然不是最佳選擇,但對我來說已經足夠了,並且可能對其他人有用。

要將文件直接保存在DB中而不在服務器端創建文件,可以將其作為BinaryStream插入。 但是,方法setBinaryStream接受3個輸入:參數索引(int),輸入流和流的長度。 因此,您必須知道文件的長度。

由於客戶端正在發送文件,因此我只要求他發送文件長度,然后使用:

dout.writeInt((int) file.length());

然后在服務器端,我的DataInputStream接收文件的長度,緊隨其后的是文件:

//receive file size (needed to save it as inputStream in DB) and file:
            DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
            int fileLength = dis.readInt();

            DB.insertFile(shorthash, filename, dis, fileLength, user);

插入文件的方法:

public void insertFile(String filename, InputStream fis, int length, String owner){
    String sql = "INSERT INTO files(filename, file, owner) VALUES(?, ?, ?)";
    try (Connection conn = DriverManager.getConnection(url);
            PreparedStatement pstmt = conn.prepareStatement(sql)) {
        pstmt.setString(1, filename);
        pstmt.setBinaryStream(2, fis, length);
        pstmt.setString(3, owner);
        pstmt.executeUpdate();
    } catch (SQLException e) {
        System.out.println(e.getMessage());
    }
}

將 PDF 轉換為 Blob 的簡單方法是先將 PDF 轉換為byte[] ,然后再將其轉換為Blob

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.rowset.serial.SerialBlob;

public static Blob pdfToBlob(File file) throws SQLException {

    byte[] bArray = new byte[1000];

    List<Byte> byteList = new ArrayList<>();

    try (FileInputStream fis = new FileInputStream(file)) {

        // Converting input file in list of bytes
        while (fis.read(bArray) > 0) {
            for (byte b : bArray)
                byteList.add(b);
        }

    } catch (IOException e) {
        e.printStackTrace();
    }

    // Converting list of bytes into array of bytes
    // as SerialBlob class takes array of bytes
    byte[] byteArray = new byte[byteList.size()];

    for (int i = 0; i < byteList.size(); i++) {
        byteArray[i] = (byte) byteList.get(i);
    }

    return new SerialBlob(byteArray);
}

如果可以,請改進上面的代碼。 希望你會發現它有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM