-
Notifications
You must be signed in to change notification settings - Fork 164
Expand file tree
/
Copy pathSampleEncoder.java
More file actions
104 lines (86 loc) · 3.75 KB
/
Copy pathSampleEncoder.java
File metadata and controls
104 lines (86 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* Command-line program encodes one file using Reed-Solomon 4+2.
*
* Copyright 2015, Backblaze, Inc.
*/
package com.backblaze.erasure;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* Command-line program encodes one file using Reed-Solomon 4+2.
*
* The one argument should be a file name, say "foo.txt". This program
* will create six files in the same directory, breaking the input file
* into four data shards, and two parity shards. The output files are
* called "foo.txt.0", "foo.txt.1", ..., and "foo.txt.5". Numbers 4
* and 5 are the parity shards.
*
* The data stored is the file size (four byte int), followed by the
* contents of the file, and then padded to a multiple of four bytes
* with zeros. The padding is because all four data shards must be
* the same size.
*/
public class SampleEncoder {
public static final int DATA_SHARDS = 4;
public static final int PARITY_SHARDS = 2;
public static final int TOTAL_SHARDS = DATA_SHARDS + PARITY_SHARDS;
public static final int BYTES_IN_INT = 4;
public static void main(String [] arguments) throws IOException {
// Parse the command line
if (arguments.length != 1) {
System.out.println("Usage: SampleEncoder <fileName>");
return;
}
final File inputFile = new File(arguments[0]);
if (!inputFile.exists()) {
System.out.println("Cannot read input file: " + inputFile);
return;
}
// Get the size of the input file. (Files bigger than
// Integer.MAX_VALUE will fail here!)
final int fileSize = (int) inputFile.length();
// Figure out how big each shard will be. The total size stored
// will be the file size (8 bytes) plus the file.
final int storedSize = fileSize + BYTES_IN_INT;
final int shardSize = (storedSize + DATA_SHARDS - 1) / DATA_SHARDS;
// Create a buffer holding the file size, followed by
// the contents of the file.
final int bufferSize = shardSize * DATA_SHARDS;
final byte [] allBytes = new byte[bufferSize];
readAllBytesPrefixedWithFileSize(inputFile, fileSize, allBytes);
// Make the buffers to hold the shards.
byte [] [] shards = new byte [TOTAL_SHARDS] [shardSize];
// Fill in the data shards
for (int i = 0; i < DATA_SHARDS; i++) {
System.arraycopy(allBytes, i * shardSize, shards[i], 0, shardSize);
}
// Use Reed-Solomon to calculate the parity.
ReedSolomon reedSolomon = ReedSolomon.create(DATA_SHARDS, PARITY_SHARDS);
reedSolomon.encodeParity(shards, 0, shardSize);
// Write out the resulting files.
for (int i = 0; i < TOTAL_SHARDS; i++) {
File outputFile = new File(
inputFile.getParentFile(),
inputFile.getName() + "." + i);
OutputStream out = new FileOutputStream(outputFile);
out.write(shards[i]);
out.close();
System.out.println("wrote " + outputFile);
}
}
private static void readAllBytesPrefixedWithFileSize(final File inputFile, final int fileSize, final byte [] allBytes) throws IOException {
final ByteBuffer buffer = ByteBuffer.wrap(allBytes).putInt(fileSize);
final FileInputStream fileInputStream = new FileInputStream(inputFile);
final DataInputStream dataInputStream = new DataInputStream(fileInputStream);
try {
dataInputStream.readFully(buffer.array(), buffer.position(), fileSize);
} finally {
dataInputStream.close();
}
}
}