[英]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.