简体   繁体   English

在 JAVA 中将文件或 byte[] 转换为 BLOB

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

I'm sending a file frome a client to a server and receive it like this:我正在将一个文件从客户端发送到服务器并像这样接收它:

            //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();

Just like it's explained in this subject .就像本主题中所解释的那样。 It's working well.它运作良好。 But the fact is, i don't really want to receive the file itself;但事实是,我真的不想接收文件本身; i want a BLOB.我想要一个 BLOB。 I've read that a BLOB is just like a byte[].我读过 BLOB 就像一个 byte[]。

In my database class (i use SQLite), i have the following table:在我的数据库 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"
            + ");";

and the following function to insert a new "file":和以下 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());
    }
}

As you can see, there's 4 columns, the file itself is in the 3rd column.如您所见,有 4 列,文件本身位于第 3 列。 In the table it's declared as a BLOB, but when i insert it i'm just doing a setBytes.在表中它被声明为 BLOB,但是当我插入它时我只是在做一个 setBytes。 I'm not sure if this is right, it's just what i've found on inte.net.我不确定这是否正确,这正是我在 inte.net 上找到的。

So, i'm receiving this file on my server, and i want to store it in my database.所以,我在我的服务器上收到这个文件,我想把它存储在我的数据库中。 If possible, i would like to avoid creating the file on server side (the line FileOutputStream fis = new FileOutputStream("receivedTest"); in my first code).如果可能的话,我想避免在服务器端创建文件(行 FileOutputStream fis = new FileOutputStream("receivedTest"); 在我的第一个代码中)。 I would like to store it directly in the database, since i receive it as a byte array i think it'll be easier this way.我想将它直接存储在数据库中,因为我将它作为字节数组接收,我认为这样会更容易。

But i don't know how to do that.但我不知道该怎么做。 Probably because i don't really understand the link between Blob and byte[].可能是因为我不太了解 Blob 和 byte[] 之间的联系。 I mean, a byte array may be too little to hold an entire file;我的意思是,字节数组可能太小而无法容纳整个文件; but a blob is ok.但是一滴没关系。 however, to insert the file in database, i insert a byte array.但是,为了将文件插入数据库,我插入了一个字节数组。 This make nonsens to me.这让我胡说八道。

EDIT:编辑:

So, i've tried two things: first, adding the file in the DB as it's done here (and pretty much everywhere i looked, it's always done that way):所以,我尝试了两件事:首先,将文件添加到数据库中,就像它在此处所做的那样(而且几乎所有我看过的地方,它总是这样做的):

//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());
    }
}

Second, insert the file as a byte array (but that won't work for big files) as it's explained inSQLite Tutorial :其次,将文件作为字节数组插入(但这不适用于大文件),如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();
    }
}

Then, when i print my DB, there is no file in it.然后,当我打印我的数据库时,里面没有文件。 Same if i try to open the DB with DB Browser.如果我尝试使用数据库浏览器打开数据库,也是如此。 The console only say:控制台只说:

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

1   admin   admin

Files:

A byte[] and a BLOB are just two different ways of talking about an arbitrary set of binary data. byte[]和BLOB只是讨论任意一组二进制数据的两种不同方式。 In Java a byte[] is a collection of binary data. 在Java中, byte[]是二进制数据的集合。 In a database BLOB stands for Binary Large Object and is the same thing. 在数据库中,BLOB代表Binary Large Object,并且是同一件事。 Just a collection of binary data. 只是二进制数据的集合。

So they are the same thing with different names depending on the frame of reference. 因此,根据参考框架的不同,它们是同一事物。 So when you store your byte[] in a blob column you're just pushing those bytes from Java into the database. 因此,当将byte[]存储在blob列中时,您只是将这些字节从Java推送到数据库中。 Then when you read them back they can be turned back into an object if you want because the DB didn't change them. 然后,当您读回它们时,如果需要,可以将它们变成一个对象,因为数据库没有更改它们。 It just stored the binary info directly. 它只是直接存储二进制信息。

You'd find if you wrote a blob from somewhere else you may not be able to turn it into an object unless you know the encoding and endianness of the stored binary data. 您会发现,如果您是从其他地方编写的Blob,则除非您知道所存储二进制数据的编码和字节序,否则可能无法将其转换为对象。

If you have a file too big to be stored in a single byte[] or you wanted to optimize how you're using memory for storage you could use a Stream to send the data to the db without holding it all in memory at the same time. 如果您的文件太大而无法存储在单个byte[]或者您想优化使用内存进行存储的方式,则可以使用Stream将数据发送到db,而无需将所有数据都保留在同一内存中时间。

Finally, if you need to turn your FileInputStream into bytes you can use Apache Commons IO like this: 最后,如果需要将FileInputStream转换为字节,则可以使用Apache Commons IO,如下所示:

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

And then store your file. 然后存储您的文件。

Insert file as a hex string 将文件作为十六进制字符串插入

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);

I've managed to find out a way; 我设法找到了一种方法。 it's still not optimal, but it's enough for me and it probably can be usefull for others. 它仍然不是最佳选择,但对我来说已经足够了,并且可能对其他人有用。

To save the file directly in the DB, without creating the file on server side, you can insert it as a BinaryStream. 要将文件直接保存在DB中而不在服务器端创建文件,可以将其作为BinaryStream插入。 However, the method setBinaryStream take 3 inputs: the parameter index (int), the input stream, and the length of the stream. 但是,方法setBinaryStream接受3个输入:参数索引(int),输入流和流的长度。 So to do so, you have to know the length of your file. 因此,您必须知道文件的长度。

Since the client is sending the file, i just ask him to send the length of the file before with: 由于客户端正在发送文件,因此我只要求他发送文件长度,然后使用:

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

then on server side my DataInputStream receive the length of the file, immediatly followed by the file: 然后在服务器端,我的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);

Insert file method: 插入文件的方法:

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());
    }
}

Simple way to convert PDF to Blob is to first convert PDF into byte[] and then convert it to Blob :将 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);
}

Please improve above code if you can.如果可以,请改进上面的代码。 Hope you will find it helpful.希望你会发现它有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM