Home » Blog » Java Fixed Width Text files using row, col type storage.

Share This Post

Featured Tutorials / Java / Tutorial

Java Fixed Width Text files using row, col type storage.

Java Fixed Width Text files using row, col type storage.

Fixed Width Delimited Files

In this article, I will demonstrate both fixed width text files and row, col based storage. What this amounts to is that each text file will be like a single sheet in a spreadsheet. Now accessing data by row col is probably not going to be a typical use. However, for certain type of report generation, it might come in handy. So in this example, we will read in the fixed width file and then get the values by accessing with given row or column. We will also have some utility methods for conversion to and from various data types. When the file is written each column width will be the width of the largest data types string representation in that column.  A file like this should be easily imported into any spreadsheet.  Note that we either need A) For the column widths to always need to be the same or B) To have some data source tell us the column widths before we load or C) Use a delimiter which makes each column one character wider such as | symbol that we used before. I think I will use the | delimiter as before. The difference here is that when the field is added the String is appended with white space to the proper length or a char array which can be converted back to a string.

Working with Java and Files Tutorial Trail
left nav arrowProperty FilesSerialized Objectsright nav arrow

 

In this first example, we display in columns and rows without space instead of |.

Reads and displays the rows.

import java.io.*;
import java.util.regex.*;

public class SheetReader {
private static String aFileName = "survey.txt";
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader(aFileName))) {
String aLine;
while ((aLine = br.readLine()) != null) {
String[] dataRecord=aLine.split(Pattern.quote("|"));
for(int i=0;i<dataRecord.length;i++)
System.out.print(dataRecord[i]+" ");
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

So as you have seen in prior articles it's very handy to create a specialized object to hold data in a given format such as a record. In this case, we need one to hold rows and then access those rows by columns. Obviously, each row in our spreadsheet is a line in the data file. Now we could put each cell in an array of arrays. In other languages, this is called a two-dimensional array. In Java, this is an Array of Arrays. The outer array will be columns and inner one rows. But instead of making the programmer use this array of arrays we will wrap it up neatly in an object that accesses it with get(col,row) and set(col,row) methods. One of the first things we must do is determine the size of the sheet in the file. Of course, if we knew it we could just hardcode it. It will be better if we can determine it. This is easy enough, the number of columns the dataRecord.length in the above code. But we don't know how many rows until we have read the entire file of rows.

The Sheet Object

import java.io.*;
import java.util.regex.*;
import java.util.*;

public class SheetReader {
private static String aFileName = "survey.txt";
Sheet sheet=null;
public class Sheet{
String[][] sheet=null;
int rows;
int cols;
public Sheet(int rows, int cols){
this.rows=rows;
this.cols=cols;
sheet=new String[rows][cols];
}
public void setData(int row, int col, String string){
sheet[row][col]=string;
}
public String getData(int row, int col){
return sheet[row][col];
}
}
public SheetReader(){
ArrayList<String> rows = new ArrayList<String>();
try (BufferedReader br = new BufferedReader(new FileReader(aFileName))) {
String aLine;
while ((aLine = br.readLine()) != null) {
rows.add(aLine);
}
Iterator<String> rowsIterator = rows.iterator();
int r=0;
while(rowsIterator.hasNext()){
String[] cols=rowsIterator.next().split(Pattern.quote("|"));
if(sheet==null)sheet= new Sheet(rows.size(),cols.length);
for(int c=0;c<cols.length;c++){
sheet.setData(r,c,cols[c]);
}
r++;
}
for(r=0;r<sheet.rows;r++){
for(int c=0;c<sheet.cols;c++)
System.out.print(sheet.getData(r,c)+" ");
System.out.println();
}
} catch (IOException e){
e.printStackTrace();
}
}

public static void main(String[] args) {
new SheetReader();
}
}

 

Next thing to do is to code the utility methods for data type conversions. We also need a way to make sure the data type when converted back to string is appended with white space to fill the cells. If a column needs to be expanded then we need a private utility method to do just that, which means expanding all the cells in that column. Also the logic for this white space fill and column expansion became complex and it had to be repeated in each setter method therefore I abstracted it out into a method called manageColumnSpace that took String for the data being stored and col number and returned a string to be stored in the cell or newly expanded column and cell.

The code below compiles yet the new code has not been tested or debugged. But this code shows what we are trying to do. If you try to store something outside the size of our sheet you will get the index out of bounds exception. So this means we may want to write some code to increase the size of the array of arrays by either adding columns or rows of white space. Then when we write the file out it will be a larger text file.
And this is the data file we will use. It's half of survey information taken in the cave. The other half is the sketching which I will not show. Though it would be a better example if I had time to make something up.

Working with data types.

cave survey|Bear Cave        |Front Sight|John J Smith      |    |    |    |     |
latitute   |51° 30' 12.11'' N|Back Sight |Albert Einstein   |    |    |    |     |
longitute  |0° 7' 39.45'' W  |Tape Smart |Adolf Hitler      |    |    |    |     |
date       |02/03/2018       |Tape Dumb  |George Washington |    |    |    |     |
survey name|north passage    |Sketcher   |Larry Gray        |    |    |    |     |
           |                 |back az    |back va           |    |    |    |     |
           |dist             |azmith     |vert angle        |up  |down|left|right|
a1         |                 |147.25     |-9.75             |    |    |    |     |
           |21.5             |302.5      |+10.5             |10.8|2   |15.3|18.9 |
a2         |                 |           |                  |    |    |    |     |
           |13.2             |265.25     |-1.25             |4   |1.2 |3.5 |1.3  |
a3         |                 |           |                  |    |    |    |     |
           |85.7             |150.75     |-4.75             |25  |5.7 |30  |55   |
a4         |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
           |                 |           |                  |    |    |    |     |
import java.io.*;
import java.util.regex.*;
import java.util.*;
import java.text.*;

public class SheetReader {
private static String aFileName = "survey.txt";
private static String outputFileName = "survey2.txt";
Sheet sheet=null;
public class Sheet{
String[][] sheet=null;
int rows;
int cols;
public String toString(){
String rowString=null;
String sheetString=null;
for(int r=0;r<rows;r++){
for(int c=0;c<cols;c++)
rowString+=sheet[r][c]+"|";
sheetString+=rowString+"\n";
rowString="";
}
return sheetString;
}
public Sheet(int rows, int cols){
this.rows=rows;
this.cols=cols;
sheet=new String[rows][cols];
}
private int getColWidth(int col){
if(sheet[0][col]==null)
return 0;
else
return sheet[0][col].length();
}
private String appendWhiteSpace(String theString, int length){
return (theString+" "+
" "+
" ").substring(0,length);
}
private void expandColWidth(int col, int w){
for(int r=0;r<rows;r++){
sheet[r][col]=appendWhiteSpace(sheet[r][col],w);
}
}
SimpleDateFormat dateFormat=new SimpleDateFormat("dd/MM/yy");

public String manageColumnSpace(String string,int col){
int w=getColWidth(col);
if(w==0)return string;
int l=string.length();
if(l<=w) return appendWhiteSpace(string,w);
else {
expandColWidth(col,l);
return string;
}
}
public int getInt(int row, int col){
return Integer.parseInt((sheet[row][col]).trim());
}
public void setInt(int row, int col, int anInt){
sheet[row][col]=manageColumnSpace(""+anInt,col);
}
public void setFloat(int row,int col,float aFloat){
sheet[row][col]=manageColumnSpace(""+aFloat,col);
}
public float getFloat(int row,int col){
return Float.parseFloat((sheet[row][col]).trim());
}
public boolean getBoolean(int row, int col){
return Boolean.parseBoolean((sheet[row][col]).trim());
}
public void setBoolean(int row, int col, boolean aBoolean){
sheet[row][col]=manageColumnSpace(""+aBoolean,col);
}
public Date getDate(int row, int col){
return new Date(sheet[row][col]);
}
public void setDate(int row, int col, Date date){
sheet[row][col]=manageColumnSpace(dateFormat.format(date),col);
}
public String getData(int row, int col){
return sheet[row][col];
}
public void setData(int row, int col, String string){

sheet[row][col]=manageColumnSpace(string,col);
}
}
public SheetReader(){
ArrayList<String> rows = new ArrayList<String>();
try (BufferedReader br = new BufferedReader(new FileReader(aFileName))) {
String aLine;
while ((aLine = br.readLine()) != null) {
rows.add(aLine);
}
Iterator<String> rowsIterator = rows.iterator();
int r=0;
while(rowsIterator.hasNext()){
String[] cols=rowsIterator.next().split(Pattern.quote("|"));
if(sheet==null)sheet= new Sheet(rows.size(),cols.length);
for(int c=0;c<cols.length;c++){
sheet.setData(r,c,cols[c]);
}
r++;
}
for(r=0;r<sheet.rows;r++){
for(int c=0;c<sheet.cols;c++)
System.out.print(sheet.getData(r,c)+" ");
System.out.println();
}
} catch (IOException e){
e.printStackTrace();
}
write();
}
public void write(){
try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputFileName))) {
String aString = sheet.toString();
bw.write(aString);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new SheetReader();
}
}

 

Without even testing the code above I'm going to move on and code the writing sheet back to file code. I am thinking the easiest way to do
this is to simply have the Sheet object have a toString() method which builds the lines appending each to a String with "\n" delimiting lines. Then all that is needed is for the write method to open the file and write the sheet.toString();  and done. We are safe most likely in that our actual data would have been over 2 gigs in bytes and each char in a string is 2 byte Unicode char. So this means we can do near 1 gig in characters in our sheet before we have problems. For our simple applications, it will probably never be an issue.

Reading and Writing the Sheet

import java.io.*;
import java.util.regex.*;
import java.util.*;
import java.text.*;

public class SheetReaderWriter {
private static String aFileName = "survey.txt";
private static String outputFileName = "survey2.txt";
Sheet sheet=null;
public class Sheet{
String[][] sheet=null;
int rows;
int cols;
public String toString(){
String rowString="";
String sheetString="";
for(int r=0;r<rows;r++){
for(int c=0;c<cols;c++)
rowString+=sheet[r][c]+"|";
sheetString+=rowString+"\n";
rowString="";
}
return sheetString;
}
public Sheet(int rows, int cols){
this.rows=rows;
this.cols=cols;
sheet=new String[rows][cols];
}
private int getColWidth(int col){
if(sheet[0][col]==null)
return 0;
else
return sheet[0][col].length();
}
private String appendWhiteSpace(String theString, int length){
return (theString+" "+
" "+
" ").substring(0,length);
}
private void expandColWidth(int col, int w){
for(int r=0;r<rows;r++){
sheet[r][col]=appendWhiteSpace(sheet[r][col],w);
}
}
SimpleDateFormat dateFormat=new SimpleDateFormat("dd/MM/yy");

public String manageColumnSpace(String string,int col){
int w=getColWidth(col);
if(w==0)return string;
int l=string.length();
if(l<=w) return appendWhiteSpace(string,w);
else {
expandColWidth(col,l);
return string;
}
}
public int getInt(int row, int col){
return Integer.parseInt((sheet[row][col]).trim());
}
public void setInt(int row, int col, int anInt){
sheet[row][col]=manageColumnSpace(""+anInt,col);
}
public void setFloat(int row,int col,float aFloat){
sheet[row][col]=manageColumnSpace(""+aFloat,col);
}
public float getFloat(int row,int col){
return Float.parseFloat((sheet[row][col]).trim());
}
public boolean getBoolean(int row, int col){
return Boolean.parseBoolean((sheet[row][col]).trim());
}
public void setBoolean(int row, int col, boolean aBoolean){
sheet[row][col]=manageColumnSpace(""+aBoolean,col);
}
public Date getDate(int row, int col){
return new Date(sheet[row][col]);
}
public void setDate(int row, int col, Date date){
sheet[row][col]=manageColumnSpace(dateFormat.format(date),col);
}
public String getData(int row, int col){
return sheet[row][col];
}
public void setData(int row, int col, String string){

sheet[row][col]=manageColumnSpace(string,col);
}
}
public SheetReaderWriter(){
ArrayList<String> rows = new ArrayList<String>();
try (BufferedReader br = new BufferedReader(new FileReader(aFileName))) {
String aLine;
while ((aLine = br.readLine()) != null) {
rows.add(aLine);
}
Iterator<String> rowsIterator = rows.iterator();
int r=0;
while(rowsIterator.hasNext()){
String[] cols=rowsIterator.next().split(Pattern.quote("|"));
if(sheet==null)sheet= new Sheet(rows.size(),cols.length);
for(int c=0;c<cols.length;c++){
sheet.setData(r,c,cols[c]);
}
r++;
}
for(r=0;r<sheet.rows;r++){
for(int c=0;c<sheet.cols;c++)
System.out.print(sheet.getData(r,c)+" ");
System.out.println();
}
} catch (IOException e){
e.printStackTrace();
}
write();
}
public void write(){
try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputFileName))) {
String aString = sheet.toString();
bw.write(aString);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new SheetReaderWriter();
}
}

So the above duplicates the file survey.txt to survey2.txt Next, we need to test some set/get methods. I will simply use each method on some cells.

Demo setting and getting data.

import java.io.*;
import java.util.regex.*;
import java.util.*;
import java.text.*;

public class SheetReaderWriter {
private static String aFileName = "survey.txt";
private static String outputFileName = "survey2.txt";
Sheet sheet=null;
public class Sheet{
String[][] sheet=null;
int rows;
int cols;
public String toString(){
String rowString="";
String sheetString="";
for(int r=0;r<rows;r++){
for(int c=0;c<cols;c++)
rowString+=sheet[r][c]+"|";
sheetString+=rowString+"\n";
rowString="";
}
return sheetString;
}
public Sheet(int rows, int cols){
this.rows=rows;
this.cols=cols;
sheet=new String[rows][cols];
}
private int getColWidth(int col){
if(sheet[0][col]==null)
return 0;
else
return sheet[0][col].length();
}
private String appendWhiteSpace(String theString, int length){
return (theString+" "+
" "+
" ").substring(0,length);
}
private void expandColWidth(int col, int w){
for(int r=0;r<rows;r++){
sheet[r][col]=appendWhiteSpace(sheet[r][col],w);
}
}
SimpleDateFormat dateFormat=new SimpleDateFormat("dd/MM/yy");
public String manageColumnSpace(String string,int col){
int w=getColWidth(col);
if(w==0)return string;
int l=string.length();
if(l<=w) return appendWhiteSpace(string,w);
else {
expandColWidth(col,l);
return string;
}
}
public int getInt(int row, int col){
return Integer.parseInt((sheet[row][col]).trim());
}
public void setInt(int row, int col, int anInt){
sheet[row][col]=manageColumnSpace(""+anInt,col);
}
public void setFloat(int row,int col,float aFloat){
sheet[row][col]=manageColumnSpace(""+aFloat,col);
}
public float getFloat(int row,int col){
return Float.parseFloat((sheet[row][col]).trim());
}
public boolean getBoolean(int row, int col){
return Boolean.parseBoolean((sheet[row][col]).trim());
}
public void setBoolean(int row, int col, boolean aBoolean){
sheet[row][col]=manageColumnSpace(""+aBoolean,col);
}
public Date getDate(int row, int col){
return new Date(sheet[row][col]);
}
public void setDate(int row, int col, Date date){
sheet[row][col]=manageColumnSpace(dateFormat.format(date),col);
}
public String getData(int row, int col){
return sheet[row][col];
}
public void setData(int row, int col, String string){

sheet[row][col]=manageColumnSpace(string,col);
}
}
public SheetReaderWriter(){
ArrayList<String> rows = new ArrayList<String>();
try (BufferedReader br = new BufferedReader(new FileReader(aFileName))) {
String aLine;
while ((aLine = br.readLine()) != null) {
rows.add(aLine);
}
Iterator<String> rowsIterator = rows.iterator();
int r=0;
while(rowsIterator.hasNext()){
String[] cols=rowsIterator.next().split(Pattern.quote("|"));
if(sheet==null)sheet= new Sheet(rows.size(),cols.length);
for(int c=0;c<cols.length;c++){
sheet.setData(r,c,cols[c]);
}
r++;
}

} catch (IOException e){
e.printStackTrace();
}
sheet.setDate(3,1,new Date("09/02/2018"));
sheet.setData(2,3,"Joseph Stalin Jr III");
sheet.setData(0,3,sheet.getData(1,3));
sheet.setFloat(9,2,sheet.getFloat(10,2)-180.0f);
sheet.setInt(10,4,sheet.getInt(10,4)+1);
sheet.setBoolean(0,4,false);
sheet.setBoolean(1,4,sheet.getBoolean(0,4));
sheet.setBoolean(2,4,true);
sheet.setBoolean(3,4,sheet.getBoolean(2,4));
write();
}
public void write(){
try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputFileName))) {
String aString = sheet.toString();
bw.write(aString);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new SheetReaderWriter();
}
}

 

So here we see how the test worked out.

cave survey|Bear Cave        |Front Sight|John J Smith      |    |    |    |     |
latitute   |51° 30' 12.11'' N|Back Sight |Albert Einstein   |    |    |    |     |
longitute  |0° 7' 39.45'' W  |Tape Smart |Adolf Hitler      |    |    |    |     |
date       |02/03/2018       |Tape Dumb  |George Washington |    |    |    |     |
survey name|north passage    |Sketcher   |Larry Gray        |    |    |    |     |
           |                 |back az    |back va           |    |    |    |     |
           |dist             |azmith     |vert angle        |up  |down|left|right|
a1         |                 |147.25     |-9.75             |    |    |    |     |
           |21.5             |302.5      |+10.5             |10.8|2   |15.3|18.9 |
a2         |                 |           |                  |    |    |    |     |
           |13.2             |265.25     |-1.25             |4   |1.2 |3.5 |1.3  |
a3         |                 |           |                  |    |    |    |     |
           |85.7             |150.75     |-4.75             |25  |5.7 |30  |55   |
a4         |                 |           |                  |    |    |    |     |

cave survey|Bear Cave        |Front Sight|Albert Einstein     |false|    |    |     |
latitute   |51° 30' 12.11'' N|Back Sight |Albert Einstein     |false|    |    |     |
longitute  |0° 7' 39.45'' W  |Tape Smart |Joseph Stalin Jr III|true |    |    |     |
date       |02/09/18         |Tape Dumb  |George Washington   |true |    |    |     |
survey name|north passage    |Sketcher   |Larry Gray          |     |    |    |     |
           |                 |back az    |back va             |     |    |    |     |
           |dist             |azmith     |vert angle          |up   |down|left|right|
a1         |                 |147.25     |-9.75               |     |    |    |     |
           |21.5             |302.5      |+10.5               |10.8 |2   |15.3|18.9 |
a2         |                 |85.25      |                    |     |    |    |     |
           |13.2             |265.25     |-1.25               |5    |1.2 |3.5 |1.3  |
a3         |                 |           |                    |     |    |    |     |
           |85.7             |150.75     |-4.75               |25   |5.7 |30  |55   |
a4         |                 |           |                    |     |    |    |     |

What else might we do?

And that is it for now. I could demonstrate doing some calculations that would be needed for cave mapping.
For example to the right after the up down left right data we could calculate using trigonometry change in vertical and horizontal distances. Also, change in e-w distance and change in n-s distance. This data would then be used to plot plan view line plot of survey or profile views of the survey.  Also, we could calculate the error in azimuth and error in the vertical angle which should be less than one degree usually. This is the difference in front and back sights. Once we do that, this is a fully functional app for aiding in cave surveying or any surveying for that matter, even above ground. The cartographer would either use the data in some CAD program or on actual physical graph paper. I don't know what you might want this type of data storage for but you now have it. Have fun.

 

 

Share This Post

Leave a Reply