1+ package mk .ukim .finki .os .examples .arraydb ;
2+
3+ import java .io .*;
4+
5+ /**
6+ * @author Riste Stojanov
7+ */
8+ public class CsvToOrderedBinaryDatabase {
9+
10+ private static final int ROW_NUMBER_BYTES = 8 ; // 1 long x 8 bytes
11+ private static final int VALUE_BYTES = 8 ; // 8 chars x 1 byte
12+ private static final int STATUS_BYTES = 1 ; // 1 char x 1 byte
13+ private static final int ADDITIONAL_CONTROL_BYTES = 4 ; // 2 for each utf string
14+ private static final long ELEMENT_SIZE = ROW_NUMBER_BYTES + VALUE_BYTES + STATUS_BYTES + ADDITIONAL_CONTROL_BYTES ;
15+ private static String CSV_FILE = "data/CsvToOrderedBinaryDatabase.csv" ;
16+ private static String DB_FILE = "data/CsvToOrderedBinaryDatabase.osdb" ;
17+
18+ public static void main (String [] args ) throws IOException {
19+ parseCsv (CSV_FILE , DB_FILE );
20+
21+ }
22+
23+ public static void parseCsv (String csvFile , String binFile ) throws IOException {
24+ // Java 8 try with resources that replaces the try-finally block
25+ // see: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
26+ try (
27+ BufferedReader csvReader = openCsv (csvFile );
28+ RandomAccessFile randomAccessFile = createOrOpenDatabase (binFile )
29+ ) {
30+ String line ;
31+ // one line at a time in memory. OK until the line is not too long
32+ // we have specification that the line is 13 characters + semicolons and spaces. It will fit in memory :)
33+ while ((line = csvReader .readLine ()) != null ) {
34+ saveLine (line , randomAccessFile );
35+ }
36+ }
37+ // how can we validate ourselves?
38+ printDatabase (binFile );
39+ }
40+
41+
42+ private static BufferedReader openCsv (String csvFile ) throws FileNotFoundException {
43+ File file = new File (csvFile );
44+ if (!file .exists ()) {
45+ throw new IllegalStateException ("csv file not found! absolutePath: "
46+ + file .getAbsolutePath ());
47+ }
48+ return new BufferedReader (new FileReader (file ));
49+ }
50+
51+ private static RandomAccessFile createOrOpenDatabase (String binFile ) throws FileNotFoundException {
52+ return new RandomAccessFile (binFile , "rw" );
53+ }
54+
55+ private static void saveLine (String line , RandomAccessFile randomAccessFile ) throws IOException {
56+ //TODO: change the code to write it in the right place
57+
58+ String [] elements = validateAndGetElements (line );
59+ //ADVICE: Always use trim() before parsing type (unless white spaces are expected)
60+ Long rowNumber = Long .parseLong (
61+ elements [0 ].trim () // .trim removes the invisible characters at the beginning and at the end of the string
62+ );
63+ String value = elements [1 ].trim ();
64+ String status = elements [2 ].trim ();
65+ validateElements (value , status );
66+ randomAccessFile .writeLong (rowNumber );
67+ // if the characters are cyrillic, there will be 2 bytes per character
68+ System .out .println ("Value length: " + value .getBytes ().length );
69+
70+ // Documentation snippet from DataOutputStream.writeUTF:
71+ // First, two bytes are written to out as if by the <code>writeShort</code>
72+ // method giving the number of bytes to follow ...
73+ randomAccessFile .writeUTF (value );
74+ System .out .println ("Status length: " + status .getBytes ().length );
75+ randomAccessFile .writeUTF (status );
76+ }
77+
78+ private static String [] validateAndGetElements (String line ) {
79+ String [] elements = line .split ("," );
80+ if (elements .length != 3 ) {
81+ throw new IllegalArgumentException ("Line does not have exactly 3 elements! line: " + line );
82+ }
83+ return elements ;
84+ }
85+
86+ private static void validateElements (String value , String status ) {
87+ if (value .length () != 8 ) {
88+ throw new IllegalArgumentException ("Invalid value length! expected 8 characters. value=" + value );
89+ }
90+ if (status .length () != 1 ) {
91+ throw new IllegalArgumentException ("Invalid value length! expected 1 characters. status=" + status );
92+ }
93+ }
94+
95+
96+ private static void printDatabase (String binFile ) throws IOException {
97+ try (
98+ RandomAccessFile randomAccessFile = new RandomAccessFile (binFile , "r" )
99+ ) {
100+ Long numberOfElements = randomAccessFile .length () / ELEMENT_SIZE ;
101+ System .out .println ("file size: " + randomAccessFile .length ());
102+ int index = 0 ;
103+ System .out .println ("number of elements: " + numberOfElements );
104+ while (index < numberOfElements ) {
105+ printElement (randomAccessFile , index );
106+ index ++;
107+ }
108+ }
109+ }
110+
111+ private static void printElement (RandomAccessFile randomAccessFile , int index ) throws IOException {
112+ byte [] valueBytes = new byte [VALUE_BYTES ];
113+ byte [] statusBytes = new byte [STATUS_BYTES ];
114+
115+ // go to the position of the element
116+ randomAccessFile .seek (index * ELEMENT_SIZE );
117+
118+ //read from the random access file
119+ Long rowNumber = randomAccessFile .readLong ();
120+
121+ String value = randomAccessFile .readUTF ();
122+ String status = randomAccessFile .readUTF ();
123+ System .out .println ("file pointer: " + randomAccessFile .getFilePointer ());
124+
125+ System .out .println (rowNumber + ", " + value + ", " + status );
126+ }
127+
128+
129+ }
0 commit comments