From aca620241a05a62e088936f3c13b86d4b8cb69f2 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Tue, 22 Jun 2021 08:58:16 +0100 Subject: [PATCH] More work on data file split/join, and added a test. --- .../java/org/qortal/storage/DataFile.java | 59 ++++++++++++++++++- src/test/java/org/qortal/test/DataTests.java | 45 ++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/qortal/test/DataTests.java diff --git a/src/main/java/org/qortal/storage/DataFile.java b/src/main/java/org/qortal/storage/DataFile.java index ce1e6203..9473487f 100644 --- a/src/main/java/org/qortal/storage/DataFile.java +++ b/src/main/java/org/qortal/storage/DataFile.java @@ -56,6 +56,7 @@ public class DataFile { public DataFile(String filePath) { this.createDataDirectory(); this.filePath = filePath; + this.chunks = new ArrayList<>(); if (!this.isInBaseDirectory(filePath)) { // Copy file to base directory @@ -123,8 +124,7 @@ public class DataFile { Path source = Paths.get(this.filePath).toAbsolutePath(); Path dest = Paths.get(outputFilePath).toAbsolutePath(); try { - Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING); - return dest.toString(); + return Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING).toString(); } catch (IOException e) { throw new IllegalStateException("Unable to copy file to data directory"); } @@ -169,7 +169,10 @@ public class DataFile { return ValidationResult.OK; } - public int split() { + public void addChunk(DataFileChunk chunk) { + this.chunks.add(chunk); + } + public int split(int chunkSize) { try { @@ -205,6 +208,48 @@ public class DataFile { return this.chunks.size(); } + public boolean join() { + // Ensure we have chunks + if (this.chunks != null && this.chunks.size() > 0) { + + // Create temporary path for joined file + Path tempPath; + try { + tempPath = Files.createTempFile(this.chunks.get(0).base58Digest(), ".tmp"); + } catch (IOException e) { + return false; + } + this.filePath = tempPath.toString(); + + // Join the chunks + File outputFile = new File(this.filePath); + try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outputFile))) { + for (DataFileChunk chunk : this.chunks) { + File sourceFile = new File(chunk.filePath); + BufferedInputStream in = new BufferedInputStream(new FileInputStream(sourceFile)); + byte[] buffer = new byte[2048]; + int inSize = -1; + while ((inSize = in.read(buffer)) != -1) { + out.write(buffer, 0, inSize); + } + in.close(); + } + out.close(); + + // Copy temporary file to data directory + this.filePath = this.copyToDataDirectory(); + Files.delete(tempPath); + + return true; + } catch (FileNotFoundException e) { + return false; + } catch (IOException e) { + return false; + } + } + return false; + } + public boolean delete() { // Delete the complete file Path path = Paths.get(this.filePath); @@ -294,6 +339,10 @@ public class DataFile { } } + public int chunkCount() { + return this.chunks.size(); + } + private File getFile() { File file = new File(this.filePath); if (file.exists()) { @@ -302,6 +351,10 @@ public class DataFile { return null; } + public String getFilePath() { + return this.filePath; + } + public byte[] digest() { File file = this.getFile(); if (file != null && file.exists()) { diff --git a/src/test/java/org/qortal/test/DataTests.java b/src/test/java/org/qortal/test/DataTests.java new file mode 100644 index 00000000..2d68d41b --- /dev/null +++ b/src/test/java/org/qortal/test/DataTests.java @@ -0,0 +1,45 @@ +package org.qortal.test; + +import org.junit.Before; +import org.junit.Test; +import org.qortal.repository.DataException; +import org.qortal.storage.DataFile; +import org.qortal.test.common.Common; + +import static org.junit.Assert.*; + +public class DataTests extends Common { + + @Before + public void beforeTest() throws DataException { + Common.useDefaultSettings(); + } + + @Test + public void testSplitAndJoin() { + String dummyDataString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + DataFile dataFile = new DataFile(dummyDataString.getBytes()); + assertTrue(dataFile.exists()); + assertEquals(62, dataFile.size()); + assertEquals("3eyjYjturyVe61grRX42bprGr3Cvw6ehTy4iknVnosDj", dataFile.base58Digest()); + + // Split into 7 chunks, each 10 bytes long + dataFile.split(10); + assertEquals(7, dataFile.chunkCount()); + + // Delete the original file + dataFile.delete(); + assertFalse(dataFile.exists()); + assertEquals(0, dataFile.size()); + + // Now rebuild the original file from the chunks + assertEquals(7, dataFile.chunkCount()); + dataFile.join(); + + // Validate that the original file is intact + assertTrue(dataFile.exists()); + assertEquals(62, dataFile.size()); + assertEquals("3eyjYjturyVe61grRX42bprGr3Cvw6ehTy4iknVnosDj", dataFile.base58Digest()); + } + +}