File 在CSV文件中传输二进制数据(图像等)

File 在CSV文件中传输二进制数据(图像等),file,csv,integration,binary-data,data-migration,File,Csv,Integration,Binary Data,Data Migration,除了以字符串、数字等形式存储的其他元数据信息外,我还有一些二进制数据要传输。我拥有的二进制数据是作为blob列存储在数据库中的图像文件,我想将blob列包括在csv文件中,并将csv文件存储在文件系统或sftp服务器中,我想它存放在哪里并不重要 如何将二进制数据存储为csv文件中的另一列?以这种方式传输二进制数据是一种好的做法吗 Base64 通常(也是正确的)方法是对二进制数据进行编码。这将使数据增大4:3倍 虽然文件通常被认为是文本文件,但您可以将原始二进制数据写入该文件 然后,该数据应该用

除了以字符串、数字等形式存储的其他元数据信息外,我还有一些二进制数据要传输。我拥有的二进制数据是作为blob列存储在数据库中的图像文件,我想将blob列包括在csv文件中,并将csv文件存储在文件系统或sftp服务器中,我想它存放在哪里并不重要

如何将二进制数据存储为csv文件中的另一列?以这种方式传输二进制数据是一种好的做法吗

Base64 通常(也是正确的)方法是对二进制数据进行编码。这将使数据增大4:3倍

虽然文件通常被认为是文本文件,但您可以将原始二进制数据写入该文件

然后,该数据应该用双引号括起来,数据中所有现有的双引号必须用另一个双引号转义。引用字段也会处理二进制数据中的任何换行,但读者必须支持这一点。如果读卡器知道它正在读取二进制数据(即,如果您自己提供读卡器),那么其中也可能有空字节,这不应该是一个问题

但是,如果您的数据必须采用某种unicode格式,则可能会出现问题

因此,一般来说,将原始二进制数据写入csv文件不是一个好的做法,最好使用
base64
编码。

如前所述,确实可以在csv中包含二进制数据,但必须以文本和csv友好的方式对该数据进行编码。如前所述,这种文本和CSV友好的明显选择是

示例应用程序 下面是一个示例应用程序的完整源代码

这个应用程序通过互联网下载一些图片。即,来自姐妹网站StackOverflow.com和StackExchange.com的徽标。下载后,这些图像被编码为Base64字符串

然后写入一个2列CSV文件。列是名称和图像数据。对于这个例子,我们有两行,上面列出的每个站点一行。请注意,Base64编码不涉及逗号或引号,因此不需要用标准CSV格式的引号将Base64括起来

为了证明这是有效的,然后读取CSV文件。图像数据从Base64解码回二进制数据。二进制数据被写入存储器。您可以自己打开PNG图像文件。它们应该看起来像&

CSV的写入和读取是使用库完成的

package work.basil.example;
导入org.apache.commons.csv.CSVFormat;
导入org.apache.commons.csv.CSVPrinter;
导入org.apache.commons.csv.CSVRecord;
导入javax.imageio.imageio;
导入java.awt.image.buffereImage;
导入java.io.*;
导入java.net.MalformedURLException;
导入java.net.URL;
导入java.nio.charset.StandardCharset;
导入java.nio.file.Files;
导入java.nio.file.Path;
导入java.nio.file.path;
导入java.util.Base64;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.Objects;
公共类CsvImager
{
//编写一个CSV文件,包含两列:图像名称、Base64数据中的图像。
私有void writeCsv(最终映射Map,最终路径)
{
对象。requirennull(映射);
CSVFormat format=CSVFormat.RFC4180.withHeader(“名称”、“图像”);
试一试(
BufferedWriter=Files.newBufferedWriter(路径,StandardCharsets.UTF_8);
CSVPrinter打印机=新的CSVPrinter(书写器,格式);
)
{
//打印行。
for(字符串键:map.keySet())
{
打印机。打印(键);
buffereImage image=Objects.requirennull(map.get(key));
ByteArrayOutputStream=新建ByteArrayOutputStream();
写入(图像,“PNG”,流);
字符串imageData=Base64.getEncoder().encodeToString(stream.toByteArray());
打印机。打印(图像数据);
printer.println();
}
}捕获(IOE异常)
{
e、 printStackTrace();
}
}
//从存储中的CSV文件读取图像。
公共映射readCsv(最终路径)
{
对象。requirennull(路径);
MapMap=Map.of();
try(BufferedReader=Files.newBufferedReader(路径))
{
map=newhashmap();
CSVFormat format=CSVFormat.RFC4180.withHeader(“名称”、“图像”).withFirstRecordAsHeader();
Iterablerecords=format.parse(读卡器);
用于(CSVRecord记录:记录)
{
String name=record.get(“name”);
字符串imageBase64=record.get(“Image”);
//System.out.println(“imageBase64:\n”+imageBase64+“\n”);
byte[]bytes=Base64.getDecoder().decode(imageBase64);
ByteArrayInputStream=新的ByteArrayInputStream(字节);
BuffereImage image=ImageIO.read(流);
地图。放置(名称、图像);
}
}捕获(IOE异常)
{
e、 printStackTrace();
}
返回图;
}
//从Internet下载图像。
私有映射fetchImages()
{
MapMap=Map.of();//初始化为空映射。
尝试
{
URL urlStackOverflow=null,urlStackExchange=null;
urlStackOverflow=新URL(“https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png" );
urlStackExchange=新URL(“https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/se/se-logo.png" );
BuffereImage imageStackOverflow=ImageIO.read(urlStackOverflow);
BuffereImage imageStackExchange=ImageIO.read(urlStackE