在 Java 中將 Avro 檔案轉換為 JSON 文件
1. 概述
Apache Avro 是一種廣泛使用的資料序列化系統,由於其效率和模式演化功能,在大數據應用中尤其受歡迎。在本教學中,我們將逐步透過 Avro 將物件轉換為 JSON,並將整個 Avro 檔案轉換為 JSON 檔案。這對於數據檢查和調試特別有用。
在當今數據驅動的世界中,處理不同數據格式的能力至關重要。 Apache Avro 通常用於需要高效能和儲存效率的系統,例如 Apache Hadoop。
2. 配置
首先,我們將 Avro 和 JSON 的依賴項新增至pom.xml
檔中。
我們為本教學新增了 Apache Avro 版本1.11.1
:
`
`
3. 將 Avro 物件轉換為 JSON
透過 Avro 將 Java 物件轉換為 JSON 涉及多個步驟,其中包括:
- 推斷/建構 Avro 架構
- 將 Java 物件轉換為 Avro
GenericRecord
,最後 - 將物件轉換為 JSON
我們將利用 Avro 的 Reflect API 從 Java 物件動態推斷模式,而不是手動定義模式。
為了示範這一點,讓我們建立一個具有兩個整數屬性x
和y
Point
類別:
`public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// Getters and setters
}`
讓我們繼續推斷架構:
`public Schema inferSchema(Point p) {
return ReflectData.get().getSchema(p.getClass());
}`
我們定義了一個方法inferSchema
並使用ReflectData
類別的getSchema
方法從point
物件推斷模式。此架構描述了欄位x
和y
及其資料類型。
接下來,讓我們從Point
物件建立GenericRecord
物件並將其轉換為 JSON:
`public String convertObjectToJson(Point p, Schema schema) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GenericDatumWriter
GenericRecord genericRecord = new GenericData.Record(schema);
genericRecord.put("x", p.getX());
genericRecord.put("y", p.getY());
Encoder encoder = EncoderFactory.get().jsonEncoder(schema, outputStream);
datumWriter.write(genericRecord, encoder);
encoder.flush();
outputStream.close();
return outputStream.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}`
convertObjectToJson
方法使用提供的架構將Point
物件轉換為 JSON 字串。首先,根據提供的模式建立一個GenericRecord
對象,用Point
對象的資料填滿它,然後使用DatumWriter
透過JsonEncoder
物件將資料傳遞到ByteArrayOutputStream
,最後,在OutputStream
物件上使用toString
方法來取得JSON 字串。
讓我們驗證一下產生的 JSON 的內容:
`private AvroFileToJsonFile avroFileToJsonFile;
private Point p;
private String expectedOutput;
@BeforeEach
public void setup() {
avroFileToJsonFile = new AvroFileToJsonFile();
p = new Point(2, 4);
expectedOutput = "{"x":2,"y":4}";
}
@Test
public void whenConvertedToJson_ThenEquals() {
String response = avroFileToJsonFile.convertObjectToJson(p, avroFileToJsonFile.inferSchema(p));
assertEquals(expectedOutput, response);
}`
4. 將 Avro 檔案轉換為 JSON 文件
將整個 Avro 檔案轉換為 JSON 檔案遵循類似的過程,但涉及從檔案中讀取。當我們在磁碟上以 Avro 格式儲存資料並需要將其轉換為更易於存取的格式(例如 JSON)時,這種情況很常見。
讓我們先定義一個方法writeAvroToFile,
它將用於將一些 Avro 資料寫入檔案:
`public void writeAvroToFile(Schema schema, List
try {
if (writeLocation.exists()) {
if (!writeLocation.delete()) {
System.err.println("Failed to delete existing file.");
return;
}
}
GenericDatumWriter
DataFileWriter
dataFileWriter.create(schema, writeLocation);
for (Point record: records) {
GenericRecord genericRecord = new GenericData.Record(schema);
genericRecord.put("x", record.getX());
genericRecord.put("y", record.getY());
dataFileWriter.append(genericRecord);
}
dataFileWriter.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error writing Avro file.");
}
}`
此方法根據提供的Schema
將Point
物件建構成 GenericRecord 實例,從而將它們轉換為 Avro 格式。 GenericDatumWrite
序列化這些記錄,然後使用DataFileWriter
將其寫入 Avro 檔案。
讓我們驗證該文件是否已寫入文件並且存在:
`private File dataLocation;
private File jsonDataLocation;
...
@BeforeEach
public void setup() {
// Load files from the resources folder
ClassLoader classLoader = getClass().getClassLoader();
dataLocation = new File(classLoader.getResource("").getFile(), "data.avro");
jsonDataLocation = new File(classLoader.getResource("").getFile(), "data.json");
...
}
...
@Test
public void whenAvroContentWrittenToFile_ThenExist(){
Schema schema = avroFileToJsonFile.inferSchema(p);
avroFileToJsonFile.writeAvroToFile(schema, List.of(p), dataLocation);
assertTrue(dataLocation.exists());
}`
接下來,我們將從儲存位置讀取檔案並將其以 JSON 格式寫回另一個檔案。
讓我們建立一個名為readAvroFromFileToJsonFile
的方法來處理這個問題:
`public void readAvroFromFileToJsonFile(File readLocation, File jsonFilePath) {
DatumReader
try {
DataFileReader
DatumWriter
Schema schema = dataFileReader.getSchema();
OutputStream fos = new FileOutputStream(jsonFilePath);
JsonEncoder jsonEncoder = EncoderFactory.get().jsonEncoder(schema, fos);
while (dataFileReader.hasNext()) {
GenericRecord record = dataFileReader.next();
System.out.println(record.toString());
jsonWriter.write(record, jsonEncoder);
jsonEncoder.flush();
}
dataFileReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}`
我們從readLocation
讀取 Avro 資料並將其作為 JSON 寫入jsonFilePath
。我們使用DataFileReader
從 Avro 檔案讀取GenericRecord
實例,然後使用JsonEncoder
和GenericDatumWriter
將這些記錄序列化為 JSON 格式。
讓我們繼續確認寫入產生檔案的 JSON 內容的內容:
`@Test
public void whenAvroFileWrittenToJsonFile_ThenJsonContentEquals() throws IOException {
avroFileToJsonFile.readAvroFromFileToJsonFile(dataLocation, jsonDataLocation);
String text = Files.readString(jsonDataLocation.toPath());
assertEquals(expectedOutput, text);
}`
5. 結論
在本文中,我們探討如何將 Avro 的內容寫入檔案、讀取它並將其儲存在 JSON 格式的檔案中,並使用範例來說明該流程。此外,值得注意的是,模式也可以儲存在單獨的文件中,而不是包含在資料中。
範例和程式碼片段的實作可以在 GitHub 上找到。